runtime: move all code to src/runtime

To prepare for merging into kata-containers repository.

Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
Peng Tao
2020-04-27 19:38:29 -07:00
parent 3b98b259b4
commit a02a8bda66
2200 changed files with 0 additions and 0 deletions

View 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.

View File

@@ -0,0 +1,996 @@
// 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 analysis
import (
"fmt"
slashpath "path"
"strconv"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
)
type referenceAnalysis struct {
schemas map[string]spec.Ref
responses map[string]spec.Ref
parameters map[string]spec.Ref
items map[string]spec.Ref
headerItems map[string]spec.Ref
parameterItems map[string]spec.Ref
allRefs map[string]spec.Ref
pathItems map[string]spec.Ref
}
func (r *referenceAnalysis) addRef(key string, ref spec.Ref) {
r.allRefs["#"+key] = ref
}
func (r *referenceAnalysis) addItemsRef(key string, items *spec.Items, location string) {
r.items["#"+key] = items.Ref
r.addRef(key, items.Ref)
if location == "header" {
// NOTE: in swagger 2.0, headers and parameters (but not body param schemas) are simple schemas
// and $ref are not supported here. However it is possible to analyze this.
r.headerItems["#"+key] = items.Ref
} else {
r.parameterItems["#"+key] = items.Ref
}
}
func (r *referenceAnalysis) addSchemaRef(key string, ref SchemaRef) {
r.schemas["#"+key] = ref.Schema.Ref
r.addRef(key, ref.Schema.Ref)
}
func (r *referenceAnalysis) addResponseRef(key string, resp *spec.Response) {
r.responses["#"+key] = resp.Ref
r.addRef(key, resp.Ref)
}
func (r *referenceAnalysis) addParamRef(key string, param *spec.Parameter) {
r.parameters["#"+key] = param.Ref
r.addRef(key, param.Ref)
}
func (r *referenceAnalysis) addPathItemRef(key string, pathItem *spec.PathItem) {
r.pathItems["#"+key] = pathItem.Ref
r.addRef(key, pathItem.Ref)
}
type patternAnalysis struct {
parameters map[string]string
headers map[string]string
items map[string]string
schemas map[string]string
allPatterns map[string]string
}
func (p *patternAnalysis) addPattern(key, pattern string) {
p.allPatterns["#"+key] = pattern
}
func (p *patternAnalysis) addParameterPattern(key, pattern string) {
p.parameters["#"+key] = pattern
p.addPattern(key, pattern)
}
func (p *patternAnalysis) addHeaderPattern(key, pattern string) {
p.headers["#"+key] = pattern
p.addPattern(key, pattern)
}
func (p *patternAnalysis) addItemsPattern(key, pattern string) {
p.items["#"+key] = pattern
p.addPattern(key, pattern)
}
func (p *patternAnalysis) addSchemaPattern(key, pattern string) {
p.schemas["#"+key] = pattern
p.addPattern(key, pattern)
}
type enumAnalysis struct {
parameters map[string][]interface{}
headers map[string][]interface{}
items map[string][]interface{}
schemas map[string][]interface{}
allEnums map[string][]interface{}
}
func (p *enumAnalysis) addEnum(key string, enum []interface{}) {
p.allEnums["#"+key] = enum
}
func (p *enumAnalysis) addParameterEnum(key string, enum []interface{}) {
p.parameters["#"+key] = enum
p.addEnum(key, enum)
}
func (p *enumAnalysis) addHeaderEnum(key string, enum []interface{}) {
p.headers["#"+key] = enum
p.addEnum(key, enum)
}
func (p *enumAnalysis) addItemsEnum(key string, enum []interface{}) {
p.items["#"+key] = enum
p.addEnum(key, enum)
}
func (p *enumAnalysis) addSchemaEnum(key string, enum []interface{}) {
p.schemas["#"+key] = enum
p.addEnum(key, enum)
}
// New takes a swagger spec object and returns an analyzed spec document.
// The analyzed document contains a number of indices that make it easier to
// reason about semantics of a swagger specification for use in code generation
// or validation etc.
func New(doc *spec.Swagger) *Spec {
a := &Spec{
spec: doc,
consumes: make(map[string]struct{}, 150),
produces: make(map[string]struct{}, 150),
authSchemes: make(map[string]struct{}, 150),
operations: make(map[string]map[string]*spec.Operation, 150),
allSchemas: make(map[string]SchemaRef, 150),
allOfs: make(map[string]SchemaRef, 150),
references: referenceAnalysis{
schemas: make(map[string]spec.Ref, 150),
pathItems: make(map[string]spec.Ref, 150),
responses: make(map[string]spec.Ref, 150),
parameters: make(map[string]spec.Ref, 150),
items: make(map[string]spec.Ref, 150),
headerItems: make(map[string]spec.Ref, 150),
parameterItems: make(map[string]spec.Ref, 150),
allRefs: make(map[string]spec.Ref, 150),
},
patterns: patternAnalysis{
parameters: make(map[string]string, 150),
headers: make(map[string]string, 150),
items: make(map[string]string, 150),
schemas: make(map[string]string, 150),
allPatterns: make(map[string]string, 150),
},
enums: enumAnalysis{
parameters: make(map[string][]interface{}, 150),
headers: make(map[string][]interface{}, 150),
items: make(map[string][]interface{}, 150),
schemas: make(map[string][]interface{}, 150),
allEnums: make(map[string][]interface{}, 150),
},
}
a.initialize()
return a
}
// Spec is an analyzed specification object. It takes a swagger spec object and turns it into a registry
// with a bunch of utility methods to act on the information in the spec.
type Spec struct {
spec *spec.Swagger
consumes map[string]struct{}
produces map[string]struct{}
authSchemes map[string]struct{}
operations map[string]map[string]*spec.Operation
references referenceAnalysis
patterns patternAnalysis
enums enumAnalysis
allSchemas map[string]SchemaRef
allOfs map[string]SchemaRef
}
func (s *Spec) reset() {
s.consumes = make(map[string]struct{}, 150)
s.produces = make(map[string]struct{}, 150)
s.authSchemes = make(map[string]struct{}, 150)
s.operations = make(map[string]map[string]*spec.Operation, 150)
s.allSchemas = make(map[string]SchemaRef, 150)
s.allOfs = make(map[string]SchemaRef, 150)
s.references.schemas = make(map[string]spec.Ref, 150)
s.references.pathItems = make(map[string]spec.Ref, 150)
s.references.responses = make(map[string]spec.Ref, 150)
s.references.parameters = make(map[string]spec.Ref, 150)
s.references.items = make(map[string]spec.Ref, 150)
s.references.headerItems = make(map[string]spec.Ref, 150)
s.references.parameterItems = make(map[string]spec.Ref, 150)
s.references.allRefs = make(map[string]spec.Ref, 150)
s.patterns.parameters = make(map[string]string, 150)
s.patterns.headers = make(map[string]string, 150)
s.patterns.items = make(map[string]string, 150)
s.patterns.schemas = make(map[string]string, 150)
s.patterns.allPatterns = make(map[string]string, 150)
s.enums.parameters = make(map[string][]interface{}, 150)
s.enums.headers = make(map[string][]interface{}, 150)
s.enums.items = make(map[string][]interface{}, 150)
s.enums.schemas = make(map[string][]interface{}, 150)
s.enums.allEnums = make(map[string][]interface{}, 150)
}
func (s *Spec) reload() {
s.reset()
s.initialize()
}
func (s *Spec) initialize() {
for _, c := range s.spec.Consumes {
s.consumes[c] = struct{}{}
}
for _, c := range s.spec.Produces {
s.produces[c] = struct{}{}
}
for _, ss := range s.spec.Security {
for k := range ss {
s.authSchemes[k] = struct{}{}
}
}
for path, pathItem := range s.AllPaths() {
s.analyzeOperations(path, &pathItem)
}
for name, parameter := range s.spec.Parameters {
refPref := slashpath.Join("/parameters", jsonpointer.Escape(name))
if parameter.Items != nil {
s.analyzeItems("items", parameter.Items, refPref, "parameter")
}
if parameter.In == "body" && parameter.Schema != nil {
s.analyzeSchema("schema", *parameter.Schema, refPref)
}
if parameter.Pattern != "" {
s.patterns.addParameterPattern(refPref, parameter.Pattern)
}
if len(parameter.Enum) > 0 {
s.enums.addParameterEnum(refPref, parameter.Enum)
}
}
for name, response := range s.spec.Responses {
refPref := slashpath.Join("/responses", jsonpointer.Escape(name))
for k, v := range response.Headers {
hRefPref := slashpath.Join(refPref, "headers", k)
if v.Items != nil {
s.analyzeItems("items", v.Items, hRefPref, "header")
}
if v.Pattern != "" {
s.patterns.addHeaderPattern(hRefPref, v.Pattern)
}
if len(v.Enum) > 0 {
s.enums.addHeaderEnum(hRefPref, v.Enum)
}
}
if response.Schema != nil {
s.analyzeSchema("schema", *response.Schema, refPref)
}
}
for name, schema := range s.spec.Definitions {
s.analyzeSchema(name, schema, "/definitions")
}
// TODO: after analyzing all things and flattening schemas etc
// resolve all the collected references to their final representations
// best put in a separate method because this could get expensive
}
func (s *Spec) analyzeOperations(path string, pi *spec.PathItem) {
// TODO: resolve refs here?
// Currently, operations declared via pathItem $ref are known only after expansion
op := pi
if pi.Ref.String() != "" {
key := slashpath.Join("/paths", jsonpointer.Escape(path))
s.references.addPathItemRef(key, pi)
}
s.analyzeOperation("GET", path, op.Get)
s.analyzeOperation("PUT", path, op.Put)
s.analyzeOperation("POST", path, op.Post)
s.analyzeOperation("PATCH", path, op.Patch)
s.analyzeOperation("DELETE", path, op.Delete)
s.analyzeOperation("HEAD", path, op.Head)
s.analyzeOperation("OPTIONS", path, op.Options)
for i, param := range op.Parameters {
refPref := slashpath.Join("/paths", jsonpointer.Escape(path), "parameters", strconv.Itoa(i))
if param.Ref.String() != "" {
s.references.addParamRef(refPref, &param)
}
if param.Pattern != "" {
s.patterns.addParameterPattern(refPref, param.Pattern)
}
if len(param.Enum) > 0 {
s.enums.addParameterEnum(refPref, param.Enum)
}
if param.Items != nil {
s.analyzeItems("items", param.Items, refPref, "parameter")
}
if param.Schema != nil {
s.analyzeSchema("schema", *param.Schema, refPref)
}
}
}
func (s *Spec) analyzeItems(name string, items *spec.Items, prefix, location string) {
if items == nil {
return
}
refPref := slashpath.Join(prefix, name)
s.analyzeItems(name, items.Items, refPref, location)
if items.Ref.String() != "" {
s.references.addItemsRef(refPref, items, location)
}
if items.Pattern != "" {
s.patterns.addItemsPattern(refPref, items.Pattern)
}
if len(items.Enum) > 0 {
s.enums.addItemsEnum(refPref, items.Enum)
}
}
func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) {
if op == nil {
return
}
for _, c := range op.Consumes {
s.consumes[c] = struct{}{}
}
for _, c := range op.Produces {
s.produces[c] = struct{}{}
}
for _, ss := range op.Security {
for k := range ss {
s.authSchemes[k] = struct{}{}
}
}
if _, ok := s.operations[method]; !ok {
s.operations[method] = make(map[string]*spec.Operation)
}
s.operations[method][path] = op
prefix := slashpath.Join("/paths", jsonpointer.Escape(path), strings.ToLower(method))
for i, param := range op.Parameters {
refPref := slashpath.Join(prefix, "parameters", strconv.Itoa(i))
if param.Ref.String() != "" {
s.references.addParamRef(refPref, &param)
}
if param.Pattern != "" {
s.patterns.addParameterPattern(refPref, param.Pattern)
}
if len(param.Enum) > 0 {
s.enums.addParameterEnum(refPref, param.Enum)
}
s.analyzeItems("items", param.Items, refPref, "parameter")
if param.In == "body" && param.Schema != nil {
s.analyzeSchema("schema", *param.Schema, refPref)
}
}
if op.Responses != nil {
if op.Responses.Default != nil {
refPref := slashpath.Join(prefix, "responses", "default")
if op.Responses.Default.Ref.String() != "" {
s.references.addResponseRef(refPref, op.Responses.Default)
}
for k, v := range op.Responses.Default.Headers {
hRefPref := slashpath.Join(refPref, "headers", k)
s.analyzeItems("items", v.Items, hRefPref, "header")
if v.Pattern != "" {
s.patterns.addHeaderPattern(hRefPref, v.Pattern)
}
}
if op.Responses.Default.Schema != nil {
s.analyzeSchema("schema", *op.Responses.Default.Schema, refPref)
}
}
for k, res := range op.Responses.StatusCodeResponses {
refPref := slashpath.Join(prefix, "responses", strconv.Itoa(k))
if res.Ref.String() != "" {
s.references.addResponseRef(refPref, &res)
}
for k, v := range res.Headers {
hRefPref := slashpath.Join(refPref, "headers", k)
s.analyzeItems("items", v.Items, hRefPref, "header")
if v.Pattern != "" {
s.patterns.addHeaderPattern(hRefPref, v.Pattern)
}
if len(v.Enum) > 0 {
s.enums.addHeaderEnum(hRefPref, v.Enum)
}
}
if res.Schema != nil {
s.analyzeSchema("schema", *res.Schema, refPref)
}
}
}
}
func (s *Spec) analyzeSchema(name string, schema spec.Schema, prefix string) {
refURI := slashpath.Join(prefix, jsonpointer.Escape(name))
schRef := SchemaRef{
Name: name,
Schema: &schema,
Ref: spec.MustCreateRef("#" + refURI),
TopLevel: prefix == "/definitions",
}
s.allSchemas["#"+refURI] = schRef
if schema.Ref.String() != "" {
s.references.addSchemaRef(refURI, schRef)
}
if schema.Pattern != "" {
s.patterns.addSchemaPattern(refURI, schema.Pattern)
}
if len(schema.Enum) > 0 {
s.enums.addSchemaEnum(refURI, schema.Enum)
}
for k, v := range schema.Definitions {
s.analyzeSchema(k, v, slashpath.Join(refURI, "definitions"))
}
for k, v := range schema.Properties {
s.analyzeSchema(k, v, slashpath.Join(refURI, "properties"))
}
for k, v := range schema.PatternProperties {
// NOTE: swagger 2.0 does not support PatternProperties.
// However it is possible to analyze this in a schema
s.analyzeSchema(k, v, slashpath.Join(refURI, "patternProperties"))
}
for i, v := range schema.AllOf {
s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "allOf"))
}
if len(schema.AllOf) > 0 {
s.allOfs["#"+refURI] = schRef
}
for i, v := range schema.AnyOf {
// NOTE: swagger 2.0 does not support anyOf constructs.
// However it is possible to analyze this in a schema
s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "anyOf"))
}
for i, v := range schema.OneOf {
// NOTE: swagger 2.0 does not support oneOf constructs.
// However it is possible to analyze this in a schema
s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "oneOf"))
}
if schema.Not != nil {
// NOTE: swagger 2.0 does not support "not" constructs.
// However it is possible to analyze this in a schema
s.analyzeSchema("not", *schema.Not, refURI)
}
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
s.analyzeSchema("additionalProperties", *schema.AdditionalProperties.Schema, refURI)
}
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
// NOTE: swagger 2.0 does not support AdditionalItems.
// However it is possible to analyze this in a schema
s.analyzeSchema("additionalItems", *schema.AdditionalItems.Schema, refURI)
}
if schema.Items != nil {
if schema.Items.Schema != nil {
s.analyzeSchema("items", *schema.Items.Schema, refURI)
}
for i, sch := range schema.Items.Schemas {
s.analyzeSchema(strconv.Itoa(i), sch, slashpath.Join(refURI, "items"))
}
}
}
// SecurityRequirement is a representation of a security requirement for an operation
type SecurityRequirement struct {
Name string
Scopes []string
}
// SecurityRequirementsFor gets the security requirements for the operation
func (s *Spec) SecurityRequirementsFor(operation *spec.Operation) [][]SecurityRequirement {
if s.spec.Security == nil && operation.Security == nil {
return nil
}
schemes := s.spec.Security
if operation.Security != nil {
schemes = operation.Security
}
result := [][]SecurityRequirement{}
for _, scheme := range schemes {
if len(scheme) == 0 {
// append a zero object for anonymous
result = append(result, []SecurityRequirement{{}})
continue
}
var reqs []SecurityRequirement
for k, v := range scheme {
if v == nil {
v = []string{}
}
reqs = append(reqs, SecurityRequirement{Name: k, Scopes: v})
}
result = append(result, reqs)
}
return result
}
// SecurityDefinitionsForRequirements gets the matching security definitions for a set of requirements
func (s *Spec) SecurityDefinitionsForRequirements(requirements []SecurityRequirement) map[string]spec.SecurityScheme {
result := make(map[string]spec.SecurityScheme)
for _, v := range requirements {
if definition, ok := s.spec.SecurityDefinitions[v.Name]; ok {
if definition != nil {
result[v.Name] = *definition
}
}
}
return result
}
// SecurityDefinitionsFor gets the matching security definitions for a set of requirements
func (s *Spec) SecurityDefinitionsFor(operation *spec.Operation) map[string]spec.SecurityScheme {
requirements := s.SecurityRequirementsFor(operation)
if len(requirements) == 0 {
return nil
}
result := make(map[string]spec.SecurityScheme)
for _, reqs := range requirements {
for _, v := range reqs {
if v.Name == "" {
// optional requirement
continue
}
if _, ok := result[v.Name]; ok {
// duplicate requirement
continue
}
if definition, ok := s.spec.SecurityDefinitions[v.Name]; ok {
if definition != nil {
result[v.Name] = *definition
}
}
}
}
return result
}
// ConsumesFor gets the mediatypes for the operation
func (s *Spec) ConsumesFor(operation *spec.Operation) []string {
if len(operation.Consumes) == 0 {
cons := make(map[string]struct{}, len(s.spec.Consumes))
for _, k := range s.spec.Consumes {
cons[k] = struct{}{}
}
return s.structMapKeys(cons)
}
cons := make(map[string]struct{}, len(operation.Consumes))
for _, c := range operation.Consumes {
cons[c] = struct{}{}
}
return s.structMapKeys(cons)
}
// ProducesFor gets the mediatypes for the operation
func (s *Spec) ProducesFor(operation *spec.Operation) []string {
if len(operation.Produces) == 0 {
prod := make(map[string]struct{}, len(s.spec.Produces))
for _, k := range s.spec.Produces {
prod[k] = struct{}{}
}
return s.structMapKeys(prod)
}
prod := make(map[string]struct{}, len(operation.Produces))
for _, c := range operation.Produces {
prod[c] = struct{}{}
}
return s.structMapKeys(prod)
}
func mapKeyFromParam(param *spec.Parameter) string {
return fmt.Sprintf("%s#%s", param.In, fieldNameFromParam(param))
}
func fieldNameFromParam(param *spec.Parameter) string {
// TODO: this should be x-go-name
if nm, ok := param.Extensions.GetString("go-name"); ok {
return nm
}
return swag.ToGoName(param.Name)
}
// ErrorOnParamFunc is a callback function to be invoked
// whenever an error is encountered while resolving references
// on parameters.
//
// This function takes as input the spec.Parameter which triggered the
// error and the error itself.
//
// If the callback function returns false, the calling function should bail.
//
// If it returns true, the calling function should continue evaluating parameters.
// A nil ErrorOnParamFunc must be evaluated as equivalent to panic().
type ErrorOnParamFunc func(spec.Parameter, error) bool
func (s *Spec) paramsAsMap(parameters []spec.Parameter, res map[string]spec.Parameter, callmeOnError ErrorOnParamFunc) {
for _, param := range parameters {
pr := param
if pr.Ref.String() != "" {
obj, _, err := pr.Ref.GetPointer().Get(s.spec)
if err != nil {
if callmeOnError != nil {
if callmeOnError(param, fmt.Errorf("invalid reference: %q", pr.Ref.String())) {
continue
}
break
} else {
panic(fmt.Sprintf("invalid reference: %q", pr.Ref.String()))
}
}
if objAsParam, ok := obj.(spec.Parameter); ok {
pr = objAsParam
} else {
if callmeOnError != nil {
if callmeOnError(param, fmt.Errorf("resolved reference is not a parameter: %q", pr.Ref.String())) {
continue
}
break
} else {
panic(fmt.Sprintf("resolved reference is not a parameter: %q", pr.Ref.String()))
}
}
}
res[mapKeyFromParam(&pr)] = pr
}
}
// ParametersFor the specified operation id.
//
// Assumes parameters properly resolve references if any and that
// such references actually resolve to a parameter object.
// Otherwise, panics.
func (s *Spec) ParametersFor(operationID string) []spec.Parameter {
return s.SafeParametersFor(operationID, nil)
}
// SafeParametersFor the specified operation id.
//
// Does not assume parameters properly resolve references or that
// such references actually resolve to a parameter object.
//
// Upon error, invoke a ErrorOnParamFunc callback with the erroneous
// parameters. If the callback is set to nil, panics upon errors.
func (s *Spec) SafeParametersFor(operationID string, callmeOnError ErrorOnParamFunc) []spec.Parameter {
gatherParams := func(pi *spec.PathItem, op *spec.Operation) []spec.Parameter {
bag := make(map[string]spec.Parameter)
s.paramsAsMap(pi.Parameters, bag, callmeOnError)
s.paramsAsMap(op.Parameters, bag, callmeOnError)
var res []spec.Parameter
for _, v := range bag {
res = append(res, v)
}
return res
}
for _, pi := range s.spec.Paths.Paths {
if pi.Get != nil && pi.Get.ID == operationID {
return gatherParams(&pi, pi.Get)
}
if pi.Head != nil && pi.Head.ID == operationID {
return gatherParams(&pi, pi.Head)
}
if pi.Options != nil && pi.Options.ID == operationID {
return gatherParams(&pi, pi.Options)
}
if pi.Post != nil && pi.Post.ID == operationID {
return gatherParams(&pi, pi.Post)
}
if pi.Patch != nil && pi.Patch.ID == operationID {
return gatherParams(&pi, pi.Patch)
}
if pi.Put != nil && pi.Put.ID == operationID {
return gatherParams(&pi, pi.Put)
}
if pi.Delete != nil && pi.Delete.ID == operationID {
return gatherParams(&pi, pi.Delete)
}
}
return nil
}
// ParamsFor the specified method and path. Aggregates them with the defaults etc, so it's all the params that
// apply for the method and path.
//
// Assumes parameters properly resolve references if any and that
// such references actually resolve to a parameter object.
// Otherwise, panics.
func (s *Spec) ParamsFor(method, path string) map[string]spec.Parameter {
return s.SafeParamsFor(method, path, nil)
}
// SafeParamsFor the specified method and path. Aggregates them with the defaults etc, so it's all the params that
// apply for the method and path.
//
// Does not assume parameters properly resolve references or that
// such references actually resolve to a parameter object.
//
// Upon error, invoke a ErrorOnParamFunc callback with the erroneous
// parameters. If the callback is set to nil, panics upon errors.
func (s *Spec) SafeParamsFor(method, path string, callmeOnError ErrorOnParamFunc) map[string]spec.Parameter {
res := make(map[string]spec.Parameter)
if pi, ok := s.spec.Paths.Paths[path]; ok {
s.paramsAsMap(pi.Parameters, res, callmeOnError)
s.paramsAsMap(s.operations[strings.ToUpper(method)][path].Parameters, res, callmeOnError)
}
return res
}
// OperationForName gets the operation for the given id
func (s *Spec) OperationForName(operationID string) (string, string, *spec.Operation, bool) {
for method, pathItem := range s.operations {
for path, op := range pathItem {
if operationID == op.ID {
return method, path, op, true
}
}
}
return "", "", nil, false
}
// OperationFor the given method and path
func (s *Spec) OperationFor(method, path string) (*spec.Operation, bool) {
if mp, ok := s.operations[strings.ToUpper(method)]; ok {
op, fn := mp[path]
return op, fn
}
return nil, false
}
// Operations gathers all the operations specified in the spec document
func (s *Spec) Operations() map[string]map[string]*spec.Operation {
return s.operations
}
func (s *Spec) structMapKeys(mp map[string]struct{}) []string {
if len(mp) == 0 {
return nil
}
result := make([]string, 0, len(mp))
for k := range mp {
result = append(result, k)
}
return result
}
// AllPaths returns all the paths in the swagger spec
func (s *Spec) AllPaths() map[string]spec.PathItem {
if s.spec == nil || s.spec.Paths == nil {
return nil
}
return s.spec.Paths.Paths
}
// OperationIDs gets all the operation ids based on method an dpath
func (s *Spec) OperationIDs() []string {
if len(s.operations) == 0 {
return nil
}
result := make([]string, 0, len(s.operations))
for method, v := range s.operations {
for p, o := range v {
if o.ID != "" {
result = append(result, o.ID)
} else {
result = append(result, fmt.Sprintf("%s %s", strings.ToUpper(method), p))
}
}
}
return result
}
// OperationMethodPaths gets all the operation ids based on method an dpath
func (s *Spec) OperationMethodPaths() []string {
if len(s.operations) == 0 {
return nil
}
result := make([]string, 0, len(s.operations))
for method, v := range s.operations {
for p := range v {
result = append(result, fmt.Sprintf("%s %s", strings.ToUpper(method), p))
}
}
return result
}
// RequiredConsumes gets all the distinct consumes that are specified in the specification document
func (s *Spec) RequiredConsumes() []string {
return s.structMapKeys(s.consumes)
}
// RequiredProduces gets all the distinct produces that are specified in the specification document
func (s *Spec) RequiredProduces() []string {
return s.structMapKeys(s.produces)
}
// RequiredSecuritySchemes gets all the distinct security schemes that are specified in the swagger spec
func (s *Spec) RequiredSecuritySchemes() []string {
return s.structMapKeys(s.authSchemes)
}
// SchemaRef is a reference to a schema
type SchemaRef struct {
Name string
Ref spec.Ref
Schema *spec.Schema
TopLevel bool
}
// SchemasWithAllOf returns schema references to all schemas that are defined
// with an allOf key
func (s *Spec) SchemasWithAllOf() (result []SchemaRef) {
for _, v := range s.allOfs {
result = append(result, v)
}
return
}
// AllDefinitions returns schema references for all the definitions that were discovered
func (s *Spec) AllDefinitions() (result []SchemaRef) {
for _, v := range s.allSchemas {
result = append(result, v)
}
return
}
// AllDefinitionReferences returns json refs for all the discovered schemas
func (s *Spec) AllDefinitionReferences() (result []string) {
for _, v := range s.references.schemas {
result = append(result, v.String())
}
return
}
// AllParameterReferences returns json refs for all the discovered parameters
func (s *Spec) AllParameterReferences() (result []string) {
for _, v := range s.references.parameters {
result = append(result, v.String())
}
return
}
// AllResponseReferences returns json refs for all the discovered responses
func (s *Spec) AllResponseReferences() (result []string) {
for _, v := range s.references.responses {
result = append(result, v.String())
}
return
}
// AllPathItemReferences returns the references for all the items
func (s *Spec) AllPathItemReferences() (result []string) {
for _, v := range s.references.pathItems {
result = append(result, v.String())
}
return
}
// AllItemsReferences returns the references for all the items in simple schemas (parameters or headers).
//
// NOTE: since Swagger 2.0 forbids $ref in simple params, this should always yield an empty slice for a valid
// Swagger 2.0 spec.
func (s *Spec) AllItemsReferences() (result []string) {
for _, v := range s.references.items {
result = append(result, v.String())
}
return
}
// AllReferences returns all the references found in the document, with possible duplicates
func (s *Spec) AllReferences() (result []string) {
for _, v := range s.references.allRefs {
result = append(result, v.String())
}
return
}
// AllRefs returns all the unique references found in the document
func (s *Spec) AllRefs() (result []spec.Ref) {
set := make(map[string]struct{})
for _, v := range s.references.allRefs {
a := v.String()
if a == "" {
continue
}
if _, ok := set[a]; !ok {
set[a] = struct{}{}
result = append(result, v)
}
}
return
}
func cloneStringMap(source map[string]string) map[string]string {
res := make(map[string]string, len(source))
for k, v := range source {
res[k] = v
}
return res
}
func cloneEnumMap(source map[string][]interface{}) map[string][]interface{} {
res := make(map[string][]interface{}, len(source))
for k, v := range source {
res[k] = v
}
return res
}
// ParameterPatterns returns all the patterns found in parameters
// the map is cloned to avoid accidental changes
func (s *Spec) ParameterPatterns() map[string]string {
return cloneStringMap(s.patterns.parameters)
}
// HeaderPatterns returns all the patterns found in response headers
// the map is cloned to avoid accidental changes
func (s *Spec) HeaderPatterns() map[string]string {
return cloneStringMap(s.patterns.headers)
}
// ItemsPatterns returns all the patterns found in simple array items
// the map is cloned to avoid accidental changes
func (s *Spec) ItemsPatterns() map[string]string {
return cloneStringMap(s.patterns.items)
}
// SchemaPatterns returns all the patterns found in schemas
// the map is cloned to avoid accidental changes
func (s *Spec) SchemaPatterns() map[string]string {
return cloneStringMap(s.patterns.schemas)
}
// AllPatterns returns all the patterns found in the spec
// the map is cloned to avoid accidental changes
func (s *Spec) AllPatterns() map[string]string {
return cloneStringMap(s.patterns.allPatterns)
}
// ParameterEnums returns all the enums found in parameters
// the map is cloned to avoid accidental changes
func (s *Spec) ParameterEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.parameters)
}
// HeaderEnums returns all the enums found in response headers
// the map is cloned to avoid accidental changes
func (s *Spec) HeaderEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.headers)
}
// ItemsEnums returns all the enums found in simple array items
// the map is cloned to avoid accidental changes
func (s *Spec) ItemsEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.items)
}
// SchemaEnums returns all the enums found in schemas
// the map is cloned to avoid accidental changes
func (s *Spec) SchemaEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.schemas)
}
// AllEnums returns all the enums found in the spec
// the map is cloned to avoid accidental changes
func (s *Spec) AllEnums() map[string][]interface{} {
return cloneEnumMap(s.enums.allEnums)
}

View File

@@ -0,0 +1,47 @@
// 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 analysis
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
)
var (
// Debug is true when the SWAGGER_DEBUG env var is not empty.
// It enables a more verbose logging of the spec analyzer.
Debug = os.Getenv("SWAGGER_DEBUG") != ""
// analysisLogger is a debug logger for this package
analysisLogger *log.Logger
)
func init() {
debugOptions()
}
func debugOptions() {
analysisLogger = log.New(os.Stdout, "analysis:", log.LstdFlags)
}
func debugLog(msg string, args ...interface{}) {
// A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog()
if Debug {
_, file1, pos1, _ := runtime.Caller(1)
analysisLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...))
}
}

View File

@@ -0,0 +1,43 @@
// 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 analysis provides methods to work with a Swagger specification document from
package go-openapi/spec.
Analyzing a specification
An analysed specification object (type Spec) provides methods to work with swagger definition.
Flattening or expanding a specification
Flattening a specification bundles all remote $ref in the main spec document.
Depending on flattening options, additional preprocessing may take place:
- full flattening: replacing all inline complex constructs by a named entry in #/definitions
- expand: replace all $ref's in the document by their expanded content
Merging several specifications
Mixin several specifications merges all Swagger constructs, and warns about found conflicts.
Fixing a specification
Unmarshalling a specification with golang json unmarshalling may lead to
some unwanted result on present but empty fields.
Analyzing a Swagger schema
Swagger schemas are analyzed to determine their complexity and qualify their content.
*/
package analysis

View File

@@ -0,0 +1,76 @@
// 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 analysis
import "github.com/go-openapi/spec"
// FixEmptyResponseDescriptions replaces empty ("") response
// descriptions in the input with "(empty)" to ensure that the
// resulting Swagger is stays valid. The problem appears to arise
// from reading in valid specs that have a explicit response
// description of "" (valid, response.description is required), but
// due to zero values being omitted upon re-serializing (omitempty) we
// lose them unless we stick some chars in there.
func FixEmptyResponseDescriptions(s *spec.Swagger) {
if s.Paths != nil {
for _, v := range s.Paths.Paths {
if v.Get != nil {
FixEmptyDescs(v.Get.Responses)
}
if v.Put != nil {
FixEmptyDescs(v.Put.Responses)
}
if v.Post != nil {
FixEmptyDescs(v.Post.Responses)
}
if v.Delete != nil {
FixEmptyDescs(v.Delete.Responses)
}
if v.Options != nil {
FixEmptyDescs(v.Options.Responses)
}
if v.Head != nil {
FixEmptyDescs(v.Head.Responses)
}
if v.Patch != nil {
FixEmptyDescs(v.Patch.Responses)
}
}
}
for k, v := range s.Responses {
FixEmptyDesc(&v)
s.Responses[k] = v
}
}
// FixEmptyDescs adds "(empty)" as the description for any Response in
// the given Responses object that doesn't already have one.
func FixEmptyDescs(rs *spec.Responses) {
FixEmptyDesc(rs.Default)
for k, v := range rs.StatusCodeResponses {
FixEmptyDesc(&v)
rs.StatusCodeResponses[k] = v
}
}
// FixEmptyDesc adds "(empty)" as the description to the given
// Response object if it doesn't already have one and isn't a
// ref. No-op on nil input.
func FixEmptyDesc(rs *spec.Response) {
if rs == nil || rs.Description != "" || rs.Ref.Ref.GetURL() != nil {
return
}
rs.Description = "(empty)"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
// +build go1.8
// 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 internal
import "net/url"
// PathUnescape provides url.PathUnescape(), with seamless
// go version support for pre-go1.8
//
// TODO: this function is currently defined in go-openapi/swag,
// but unexported. We might chose to export it, or simple phase
// out pre-go1.8 support.
func PathUnescape(path string) (string, error) {
return url.PathUnescape(path)
}

View File

@@ -0,0 +1,29 @@
// +build !go1.8
// 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 internal
import "net/url"
// PathUnescape provides url.PathUnescape(), with seamless
// go version support for pre-go1.8
//
// TODO: this function is currently defined in go-openapi/swag,
// but unexported. We might chose to export it, or simple phase
// out pre-go1.8 support.
func PathUnescape(path string) (string, error) {
return url.QueryUnescape(path)
}

View File

@@ -0,0 +1,334 @@
// 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 analysis
import (
"fmt"
"reflect"
"github.com/go-openapi/spec"
)
// Mixin modifies the primary swagger spec by adding the paths and
// definitions from the mixin specs. Top level parameters and
// responses from the mixins are also carried over. Operation id
// collisions are avoided by appending "Mixin<N>" but only if
// needed.
//
// The following parts of primary are never modified by merging:
// - Info
// - BasePath
// - Host
// - ExternalDocs
//
// Consider calling FixEmptyResponseDescriptions() on the modified primary
// if you read them from storage and they are valid to start with.
//
// Entries in "paths", "definitions", "parameters" and "responses" are
// added to the primary in the order of the given mixins. If the entry
// already exists in primary it is skipped with a warning message.
//
// The count of skipped entries (from collisions) is returned so any
// deviation from the number expected can flag a warning in your build
// scripts. Carefully review the collisions before accepting them;
// consider renaming things if possible.
//
// No key normalization takes place (paths, type defs,
// etc). Ensure they are canonical if your downstream tools do
// key normalization of any form.
//
// Merging schemes (http, https), and consumers/producers do not account for
// collisions.
func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
skipped := make([]string, 0, len(mixins))
opIds := getOpIds(primary)
initPrimary(primary)
for i, m := range mixins {
skipped = append(skipped, mergeConsumes(primary, m)...)
skipped = append(skipped, mergeProduces(primary, m)...)
skipped = append(skipped, mergeTags(primary, m)...)
skipped = append(skipped, mergeSchemes(primary, m)...)
skipped = append(skipped, mergeSecurityDefinitions(primary, m)...)
skipped = append(skipped, mergeSecurityRequirements(primary, m)...)
skipped = append(skipped, mergeDefinitions(primary, m)...)
// merging paths requires a map of operationIDs to work with
skipped = append(skipped, mergePaths(primary, m, opIds, i)...)
skipped = append(skipped, mergeParameters(primary, m)...)
skipped = append(skipped, mergeResponses(primary, m)...)
}
return skipped
}
// getOpIds extracts all the paths.<path>.operationIds from the given
// spec and returns them as the keys in a map with 'true' values.
func getOpIds(s *spec.Swagger) map[string]bool {
rv := make(map[string]bool)
if s.Paths == nil {
return rv
}
for _, v := range s.Paths.Paths {
piops := pathItemOps(v)
for _, op := range piops {
rv[op.ID] = true
}
}
return rv
}
func pathItemOps(p spec.PathItem) []*spec.Operation {
var rv []*spec.Operation
rv = appendOp(rv, p.Get)
rv = appendOp(rv, p.Put)
rv = appendOp(rv, p.Post)
rv = appendOp(rv, p.Delete)
rv = appendOp(rv, p.Head)
rv = appendOp(rv, p.Patch)
return rv
}
func appendOp(ops []*spec.Operation, op *spec.Operation) []*spec.Operation {
if op == nil {
return ops
}
return append(ops, op)
}
func mergeSecurityDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for k, v := range m.SecurityDefinitions {
if _, exists := primary.SecurityDefinitions[k]; exists {
warn := fmt.Sprintf(
"SecurityDefinitions entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
skipped = append(skipped, warn)
continue
}
primary.SecurityDefinitions[k] = v
}
return
}
func mergeSecurityRequirements(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for _, v := range m.Security {
found := false
for _, vv := range primary.Security {
if reflect.DeepEqual(v, vv) {
found = true
break
}
}
if found {
warn := fmt.Sprintf(
"Security requirement: '%v' already exists in primary or higher priority mixin, skipping\n", v)
skipped = append(skipped, warn)
continue
}
primary.Security = append(primary.Security, v)
}
return
}
func mergeDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for k, v := range m.Definitions {
// assume name collisions represent IDENTICAL type. careful.
if _, exists := primary.Definitions[k]; exists {
warn := fmt.Sprintf(
"definitions entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
skipped = append(skipped, warn)
continue
}
primary.Definitions[k] = v
}
return
}
func mergePaths(primary *spec.Swagger, m *spec.Swagger, opIds map[string]bool, mixIndex int) (skipped []string) {
if m.Paths != nil {
for k, v := range m.Paths.Paths {
if _, exists := primary.Paths.Paths[k]; exists {
warn := fmt.Sprintf(
"paths entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
skipped = append(skipped, warn)
continue
}
// Swagger requires that operationIds be
// unique within a spec. If we find a
// collision we append "Mixin0" to the
// operatoinId we are adding, where 0 is mixin
// index. We assume that operationIds with
// all the proivded specs are already unique.
piops := pathItemOps(v)
for _, piop := range piops {
if opIds[piop.ID] {
piop.ID = fmt.Sprintf("%v%v%v", piop.ID, "Mixin", mixIndex)
}
opIds[piop.ID] = true
}
primary.Paths.Paths[k] = v
}
}
return
}
func mergeParameters(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for k, v := range m.Parameters {
// could try to rename on conflict but would
// have to fix $refs in the mixin. Complain
// for now
if _, exists := primary.Parameters[k]; exists {
warn := fmt.Sprintf(
"top level parameters entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
skipped = append(skipped, warn)
continue
}
primary.Parameters[k] = v
}
return
}
func mergeResponses(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for k, v := range m.Responses {
// could try to rename on conflict but would
// have to fix $refs in the mixin. Complain
// for now
if _, exists := primary.Responses[k]; exists {
warn := fmt.Sprintf(
"top level responses entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
skipped = append(skipped, warn)
continue
}
primary.Responses[k] = v
}
return
}
func mergeConsumes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for _, v := range m.Consumes {
found := false
for _, vv := range primary.Consumes {
if v == vv {
found = true
break
}
}
if found {
// no warning here: we just skip it
continue
}
primary.Consumes = append(primary.Consumes, v)
}
return
}
func mergeProduces(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for _, v := range m.Produces {
found := false
for _, vv := range primary.Produces {
if v == vv {
found = true
break
}
}
if found {
// no warning here: we just skip it
continue
}
primary.Produces = append(primary.Produces, v)
}
return
}
func mergeTags(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for _, v := range m.Tags {
found := false
for _, vv := range primary.Tags {
if v.Name == vv.Name {
found = true
break
}
}
if found {
warn := fmt.Sprintf(
"top level tags entry with name '%v' already exists in primary or higher priority mixin, skipping\n", v.Name)
skipped = append(skipped, warn)
continue
}
primary.Tags = append(primary.Tags, v)
}
return
}
func mergeSchemes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
for _, v := range m.Schemes {
found := false
for _, vv := range primary.Schemes {
if v == vv {
found = true
break
}
}
if found {
// no warning here: we just skip it
continue
}
primary.Schemes = append(primary.Schemes, v)
}
return
}
func initPrimary(primary *spec.Swagger) {
if primary.SecurityDefinitions == nil {
primary.SecurityDefinitions = make(map[string]*spec.SecurityScheme)
}
if primary.Security == nil {
primary.Security = make([]map[string][]string, 0, 10)
}
if primary.Produces == nil {
primary.Produces = make([]string, 0, 10)
}
if primary.Consumes == nil {
primary.Consumes = make([]string, 0, 10)
}
if primary.Tags == nil {
primary.Tags = make([]spec.Tag, 0, 10)
}
if primary.Schemes == nil {
primary.Schemes = make([]string, 0, 10)
}
if primary.Paths == nil {
primary.Paths = &spec.Paths{Paths: make(map[string]spec.PathItem)}
}
if primary.Paths.Paths == nil {
primary.Paths.Paths = make(map[string]spec.PathItem)
}
if primary.Definitions == nil {
primary.Definitions = make(spec.Definitions)
}
if primary.Parameters == nil {
primary.Parameters = make(map[string]spec.Parameter)
}
if primary.Responses == nil {
primary.Responses = make(map[string]spec.Response)
}
}

View File

@@ -0,0 +1,240 @@
package analysis
import (
"fmt"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
)
// SchemaOpts configures the schema analyzer
type SchemaOpts struct {
Schema *spec.Schema
Root interface{}
BasePath string
_ struct{}
}
// Schema analysis, will classify the schema according to known
// patterns.
func Schema(opts SchemaOpts) (*AnalyzedSchema, error) {
if opts.Schema == nil {
return nil, fmt.Errorf("no schema to analyze")
}
a := &AnalyzedSchema{
schema: opts.Schema,
root: opts.Root,
basePath: opts.BasePath,
}
a.initializeFlags()
a.inferKnownType()
a.inferEnum()
a.inferBaseType()
if err := a.inferMap(); err != nil {
return nil, err
}
if err := a.inferArray(); err != nil {
return nil, err
}
if err := a.inferTuple(); err != nil {
// NOTE(fredbi): currently, inferTuple() never returns an error
return nil, err
}
if err := a.inferFromRef(); err != nil {
return nil, err
}
a.inferSimpleSchema()
return a, nil
}
// AnalyzedSchema indicates what the schema represents
type AnalyzedSchema struct {
schema *spec.Schema
root interface{}
basePath string
hasProps bool
hasAllOf bool
hasItems bool
hasAdditionalProps bool
hasAdditionalItems bool
hasRef bool
IsKnownType bool
IsSimpleSchema bool
IsArray bool
IsSimpleArray bool
IsMap bool
IsSimpleMap bool
IsExtendedObject bool
IsTuple bool
IsTupleWithExtra bool
IsBaseType bool
IsEnum bool
}
// Inherits copies value fields from other onto this schema
func (a *AnalyzedSchema) inherits(other *AnalyzedSchema) {
if other == nil {
return
}
a.hasProps = other.hasProps
a.hasAllOf = other.hasAllOf
a.hasItems = other.hasItems
a.hasAdditionalItems = other.hasAdditionalItems
a.hasAdditionalProps = other.hasAdditionalProps
a.hasRef = other.hasRef
a.IsKnownType = other.IsKnownType
a.IsSimpleSchema = other.IsSimpleSchema
a.IsArray = other.IsArray
a.IsSimpleArray = other.IsSimpleArray
a.IsMap = other.IsMap
a.IsSimpleMap = other.IsSimpleMap
a.IsExtendedObject = other.IsExtendedObject
a.IsTuple = other.IsTuple
a.IsTupleWithExtra = other.IsTupleWithExtra
a.IsBaseType = other.IsBaseType
a.IsEnum = other.IsEnum
}
func (a *AnalyzedSchema) inferFromRef() error {
if a.hasRef {
sch := new(spec.Schema)
sch.Ref = a.schema.Ref
err := spec.ExpandSchema(sch, a.root, nil)
if err != nil {
return err
}
if sch != nil {
// NOTE(fredbi): currently the only cause for errors in
// unresolved ref. Since spec.ExpandSchema() expands the
// schema recursively, there is no chance to get there,
// until we add more causes for error in this schema analysis.
rsch, err := Schema(SchemaOpts{
Schema: sch,
Root: a.root,
BasePath: a.basePath,
})
if err != nil {
return err
}
a.inherits(rsch)
}
}
return nil
}
func (a *AnalyzedSchema) inferSimpleSchema() {
a.IsSimpleSchema = a.IsKnownType || a.IsSimpleArray || a.IsSimpleMap
}
func (a *AnalyzedSchema) inferKnownType() {
tpe := a.schema.Type
format := a.schema.Format
a.IsKnownType = tpe.Contains("boolean") ||
tpe.Contains("integer") ||
tpe.Contains("number") ||
tpe.Contains("string") ||
(format != "" && strfmt.Default.ContainsName(format)) ||
(a.isObjectType() && !a.hasProps && !a.hasAllOf && !a.hasAdditionalProps && !a.hasAdditionalItems)
}
func (a *AnalyzedSchema) inferMap() error {
if a.isObjectType() {
hasExtra := a.hasProps || a.hasAllOf
a.IsMap = a.hasAdditionalProps && !hasExtra
a.IsExtendedObject = a.hasAdditionalProps && hasExtra
if a.IsMap {
if a.schema.AdditionalProperties.Schema != nil {
msch, err := Schema(SchemaOpts{
Schema: a.schema.AdditionalProperties.Schema,
Root: a.root,
BasePath: a.basePath,
})
if err != nil {
return err
}
a.IsSimpleMap = msch.IsSimpleSchema
} else if a.schema.AdditionalProperties.Allows {
a.IsSimpleMap = true
}
}
}
return nil
}
func (a *AnalyzedSchema) inferArray() error {
// an array has Items defined as an object schema, otherwise we qualify this JSON array as a tuple
// (yes, even if the Items array contains only one element).
// arrays in JSON schema may be unrestricted (i.e no Items specified).
// Note that arrays in Swagger MUST have Items. Nonetheless, we analyze unrestricted arrays.
//
// NOTE: the spec package misses the distinction between:
// items: [] and items: {}, so we consider both arrays here.
a.IsArray = a.isArrayType() && (a.schema.Items == nil || a.schema.Items.Schemas == nil)
if a.IsArray && a.hasItems {
if a.schema.Items.Schema != nil {
itsch, err := Schema(SchemaOpts{
Schema: a.schema.Items.Schema,
Root: a.root,
BasePath: a.basePath,
})
if err != nil {
return err
}
a.IsSimpleArray = itsch.IsSimpleSchema
}
}
if a.IsArray && !a.hasItems {
a.IsSimpleArray = true
}
return nil
}
func (a *AnalyzedSchema) inferTuple() error {
tuple := a.hasItems && a.schema.Items.Schemas != nil
a.IsTuple = tuple && !a.hasAdditionalItems
a.IsTupleWithExtra = tuple && a.hasAdditionalItems
return nil
}
func (a *AnalyzedSchema) inferBaseType() {
if a.isObjectType() {
a.IsBaseType = a.schema.Discriminator != ""
}
}
func (a *AnalyzedSchema) inferEnum() {
a.IsEnum = len(a.schema.Enum) > 0
}
func (a *AnalyzedSchema) initializeFlags() {
a.hasProps = len(a.schema.Properties) > 0
a.hasAllOf = len(a.schema.AllOf) > 0
a.hasRef = a.schema.Ref.String() != ""
a.hasItems = a.schema.Items != nil &&
(a.schema.Items.Schema != nil || len(a.schema.Items.Schemas) > 0)
a.hasAdditionalProps = a.schema.AdditionalProperties != nil &&
(a.schema.AdditionalProperties != nil || a.schema.AdditionalProperties.Allows)
a.hasAdditionalItems = a.schema.AdditionalItems != nil &&
(a.schema.AdditionalItems.Schema != nil || a.schema.AdditionalItems.Allows)
}
func (a *AnalyzedSchema) isObjectType() bool {
return !a.hasRef && (a.schema.Type == nil || a.schema.Type.Contains("") || a.schema.Type.Contains("object"))
}
func (a *AnalyzedSchema) isArrayType() bool {
return !a.hasRef && (a.schema.Type != nil && a.schema.Type.Contains("array"))
}

202
src/runtime/vendor/github.com/go-openapi/errors/LICENSE generated vendored Normal file
View 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.

166
src/runtime/vendor/github.com/go-openapi/errors/api.go generated vendored Normal file
View File

@@ -0,0 +1,166 @@
// 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 errors
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"strings"
)
// DefaultHTTPCode is used when the error Code cannot be used as an HTTP code.
var DefaultHTTPCode = 422
// Error represents a error interface all swagger framework errors implement
type Error interface {
error
Code() int32
}
type apiError struct {
code int32
message string
}
func (a *apiError) Error() string {
return a.message
}
func (a *apiError) Code() int32 {
return a.code
}
// New creates a new API error with a code and a message
func New(code int32, message string, args ...interface{}) Error {
if len(args) > 0 {
return &apiError{code, fmt.Sprintf(message, args...)}
}
return &apiError{code, message}
}
// NotFound creates a new not found error
func NotFound(message string, args ...interface{}) Error {
if message == "" {
message = "Not found"
}
return New(http.StatusNotFound, fmt.Sprintf(message, args...))
}
// NotImplemented creates a new not implemented error
func NotImplemented(message string) Error {
return New(http.StatusNotImplemented, message)
}
// MethodNotAllowedError represents an error for when the path matches but the method doesn't
type MethodNotAllowedError struct {
code int32
Allowed []string
message string
}
func (m *MethodNotAllowedError) Error() string {
return m.message
}
// Code the error code
func (m *MethodNotAllowedError) Code() int32 {
return m.code
}
func errorAsJSON(err Error) []byte {
b, _ := json.Marshal(struct {
Code int32 `json:"code"`
Message string `json:"message"`
}{err.Code(), err.Error()})
return b
}
func flattenComposite(errs *CompositeError) *CompositeError {
var res []error
for _, er := range errs.Errors {
switch e := er.(type) {
case *CompositeError:
if len(e.Errors) > 0 {
flat := flattenComposite(e)
if len(flat.Errors) > 0 {
res = append(res, flat.Errors...)
}
}
default:
if e != nil {
res = append(res, e)
}
}
}
return CompositeValidationError(res...)
}
// MethodNotAllowed creates a new method not allowed error
func MethodNotAllowed(requested string, allow []string) Error {
msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ","))
return &MethodNotAllowedError{code: http.StatusMethodNotAllowed, Allowed: allow, message: msg}
}
const head = "HEAD"
// ServeError the error handler interface implementation
func ServeError(rw http.ResponseWriter, r *http.Request, err error) {
rw.Header().Set("Content-Type", "application/json")
switch e := err.(type) {
case *CompositeError:
er := flattenComposite(e)
// strips composite errors to first element only
if len(er.Errors) > 0 {
ServeError(rw, r, er.Errors[0])
} else {
// guard against empty CompositeError (invalid construct)
ServeError(rw, r, nil)
}
case *MethodNotAllowedError:
rw.Header().Add("Allow", strings.Join(err.(*MethodNotAllowedError).Allowed, ","))
rw.WriteHeader(asHTTPCode(int(e.Code())))
if r == nil || r.Method != head {
_, _ = rw.Write(errorAsJSON(e))
}
case Error:
value := reflect.ValueOf(e)
if value.Kind() == reflect.Ptr && value.IsNil() {
rw.WriteHeader(http.StatusInternalServerError)
_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
return
}
rw.WriteHeader(asHTTPCode(int(e.Code())))
if r == nil || r.Method != head {
_, _ = rw.Write(errorAsJSON(e))
}
case nil:
rw.WriteHeader(http.StatusInternalServerError)
_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
default:
rw.WriteHeader(http.StatusInternalServerError)
if r == nil || r.Method != head {
_, _ = rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error())))
}
}
}
func asHTTPCode(input int) int {
if input >= 600 {
return DefaultHTTPCode
}
return input
}

View File

@@ -0,0 +1,20 @@
// 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 errors
// Unauthenticated returns an unauthenticated error
func Unauthenticated(scheme string) Error {
return New(401, "unauthenticated for %s", scheme)
}

28
src/runtime/vendor/github.com/go-openapi/errors/doc.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
// 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 errors provides an Error interface and several concrete types
implementing this interface to manage API errors and JSON-schema validation
errors.
A middleware handler ServeError() is provided to serve the errors types
it defines.
It is used throughout the various go-openapi toolkit libraries
(https://github.com/go-openapi).
*/
package errors

View File

@@ -0,0 +1,85 @@
// 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 errors
import (
"fmt"
"net/http"
)
// Validation represents a failure of a precondition
type Validation struct {
code int32
Name string
In string
Value interface{}
message string
Values []interface{}
}
func (e *Validation) Error() string {
return e.message
}
// Code the error code
func (e *Validation) Code() int32 {
return e.code
}
// ValidateName produces an error message name for an aliased property
func (e *Validation) ValidateName(name string) *Validation {
if e.Name == "" && name != "" {
e.Name = name
e.message = name + e.message
}
return e
}
const (
contentTypeFail = `unsupported media type %q, only %v are allowed`
responseFormatFail = `unsupported media type requested, only %v are available`
)
// InvalidContentType error for an invalid content type
func InvalidContentType(value string, allowed []string) *Validation {
values := make([]interface{}, 0, len(allowed))
for _, v := range allowed {
values = append(values, v)
}
return &Validation{
code: http.StatusUnsupportedMediaType,
Name: "Content-Type",
In: "header",
Value: value,
Values: values,
message: fmt.Sprintf(contentTypeFail, value, allowed),
}
}
// InvalidResponseFormat error for an unacceptable response format request
func InvalidResponseFormat(value string, allowed []string) *Validation {
values := make([]interface{}, 0, len(allowed))
for _, v := range allowed {
values = append(values, v)
}
return &Validation{
code: http.StatusNotAcceptable,
Name: "Accept",
In: "header",
Value: value,
Values: values,
message: fmt.Sprintf(responseFormatFail, allowed),
}
}

View File

@@ -0,0 +1,51 @@
// 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 errors
import (
"bytes"
"fmt"
"strings"
)
// APIVerificationFailed is an error that contains all the missing info for a mismatched section
// between the api registrations and the api spec
type APIVerificationFailed struct {
Section string
MissingSpecification []string
MissingRegistration []string
}
//
func (v *APIVerificationFailed) Error() string {
buf := bytes.NewBuffer(nil)
hasRegMissing := len(v.MissingRegistration) > 0
hasSpecMissing := len(v.MissingSpecification) > 0
if hasRegMissing {
buf.WriteString(fmt.Sprintf("missing [%s] %s registrations", strings.Join(v.MissingRegistration, ", "), v.Section))
}
if hasRegMissing && hasSpecMissing {
buf.WriteString("\n")
}
if hasSpecMissing {
buf.WriteString(fmt.Sprintf("missing from spec file [%s] %s", strings.Join(v.MissingSpecification, ", "), v.Section))
}
return buf.String()
}

View File

@@ -0,0 +1,59 @@
// 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 errors
import "fmt"
// ParseError respresents a parsing error
type ParseError struct {
code int32
Name string
In string
Value string
Reason error
message string
}
func (e *ParseError) Error() string {
return e.message
}
// Code returns the http status code for this error
func (e *ParseError) Code() int32 {
return e.code
}
const (
parseErrorTemplContent = `parsing %s %s from %q failed, because %s`
parseErrorTemplContentNoIn = `parsing %s from %q failed, because %s`
)
// NewParseError creates a new parse error
func NewParseError(name, in, value string, reason error) *ParseError {
var msg string
if in == "" {
msg = fmt.Sprintf(parseErrorTemplContentNoIn, name, value, reason)
} else {
msg = fmt.Sprintf(parseErrorTemplContent, name, in, value, reason)
}
return &ParseError{
code: 400,
Name: name,
In: in,
Value: value,
Reason: reason,
message: msg,
}
}

View File

@@ -0,0 +1,562 @@
// 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 errors
import (
"fmt"
"strings"
)
const (
invalidType = "%s is an invalid type name"
typeFail = "%s in %s must be of type %s"
typeFailWithData = "%s in %s must be of type %s: %q"
typeFailWithError = "%s in %s must be of type %s, because: %s"
requiredFail = "%s in %s is required"
tooLongMessage = "%s in %s should be at most %d chars long"
tooShortMessage = "%s in %s should be at least %d chars long"
patternFail = "%s in %s should match '%s'"
enumFail = "%s in %s should be one of %v"
multipleOfFail = "%s in %s should be a multiple of %v"
maxIncFail = "%s in %s should be less than or equal to %v"
maxExcFail = "%s in %s should be less than %v"
minIncFail = "%s in %s should be greater than or equal to %v"
minExcFail = "%s in %s should be greater than %v"
uniqueFail = "%s in %s shouldn't contain duplicates"
maxItemsFail = "%s in %s should have at most %d items"
minItemsFail = "%s in %s should have at least %d items"
typeFailNoIn = "%s must be of type %s"
typeFailWithDataNoIn = "%s must be of type %s: %q"
typeFailWithErrorNoIn = "%s must be of type %s, because: %s"
requiredFailNoIn = "%s is required"
tooLongMessageNoIn = "%s should be at most %d chars long"
tooShortMessageNoIn = "%s should be at least %d chars long"
patternFailNoIn = "%s should match '%s'"
enumFailNoIn = "%s should be one of %v"
multipleOfFailNoIn = "%s should be a multiple of %v"
maxIncFailNoIn = "%s should be less than or equal to %v"
maxExcFailNoIn = "%s should be less than %v"
minIncFailNoIn = "%s should be greater than or equal to %v"
minExcFailNoIn = "%s should be greater than %v"
uniqueFailNoIn = "%s shouldn't contain duplicates"
maxItemsFailNoIn = "%s should have at most %d items"
minItemsFailNoIn = "%s should have at least %d items"
noAdditionalItems = "%s in %s can't have additional items"
noAdditionalItemsNoIn = "%s can't have additional items"
tooFewProperties = "%s in %s should have at least %d properties"
tooFewPropertiesNoIn = "%s should have at least %d properties"
tooManyProperties = "%s in %s should have at most %d properties"
tooManyPropertiesNoIn = "%s should have at most %d properties"
unallowedProperty = "%s.%s in %s is a forbidden property"
unallowedPropertyNoIn = "%s.%s is a forbidden property"
failedAllPatternProps = "%s.%s in %s failed all pattern properties"
failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v"
)
// All code responses can be used to differentiate errors for different handling
// by the consuming program
const (
// CompositeErrorCode remains 422 for backwards-compatibility
// and to separate it from validation errors with cause
CompositeErrorCode = 422
// InvalidTypeCode is used for any subclass of invalid types
InvalidTypeCode = 600 + iota
RequiredFailCode
TooLongFailCode
TooShortFailCode
PatternFailCode
EnumFailCode
MultipleOfFailCode
MaxFailCode
MinFailCode
UniqueFailCode
MaxItemsFailCode
MinItemsFailCode
NoAdditionalItemsCode
TooFewPropertiesCode
TooManyPropertiesCode
UnallowedPropertyCode
FailedAllPatternPropsCode
MultipleOfMustBePositiveCode
)
// CompositeError is an error that groups several errors together
type CompositeError struct {
Errors []error
code int32
message string
}
// Code for this error
func (c *CompositeError) Code() int32 {
return c.code
}
func (c *CompositeError) Error() string {
if len(c.Errors) > 0 {
msgs := []string{c.message + ":"}
for _, e := range c.Errors {
msgs = append(msgs, e.Error())
}
return strings.Join(msgs, "\n")
}
return c.message
}
// CompositeValidationError an error to wrap a bunch of other errors
func CompositeValidationError(errors ...error) *CompositeError {
return &CompositeError{
code: CompositeErrorCode,
Errors: append([]error{}, errors...),
message: "validation failure list",
}
}
// FailedAllPatternProperties an error for when the property doesn't match a pattern
func FailedAllPatternProperties(name, in, key string) *Validation {
msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
if in == "" {
msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
}
return &Validation{
code: FailedAllPatternPropsCode,
Name: name,
In: in,
Value: key,
message: msg,
}
}
// PropertyNotAllowed an error for when the property doesn't match a pattern
func PropertyNotAllowed(name, in, key string) *Validation {
msg := fmt.Sprintf(unallowedProperty, name, key, in)
if in == "" {
msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
}
return &Validation{
code: UnallowedPropertyCode,
Name: name,
In: in,
Value: key,
message: msg,
}
}
// TooFewProperties an error for an object with too few properties
func TooFewProperties(name, in string, n int64) *Validation {
msg := fmt.Sprintf(tooFewProperties, name, in, n)
if in == "" {
msg = fmt.Sprintf(tooFewPropertiesNoIn, name, n)
}
return &Validation{
code: TooFewPropertiesCode,
Name: name,
In: in,
Value: n,
message: msg,
}
}
// TooManyProperties an error for an object with too many properties
func TooManyProperties(name, in string, n int64) *Validation {
msg := fmt.Sprintf(tooManyProperties, name, in, n)
if in == "" {
msg = fmt.Sprintf(tooManyPropertiesNoIn, name, n)
}
return &Validation{
code: TooManyPropertiesCode,
Name: name,
In: in,
Value: n,
message: msg,
}
}
// AdditionalItemsNotAllowed an error for invalid additional items
func AdditionalItemsNotAllowed(name, in string) *Validation {
msg := fmt.Sprintf(noAdditionalItems, name, in)
if in == "" {
msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
}
return &Validation{
code: NoAdditionalItemsCode,
Name: name,
In: in,
message: msg,
}
}
// InvalidCollectionFormat another flavor of invalid type error
func InvalidCollectionFormat(name, in, format string) *Validation {
return &Validation{
code: InvalidTypeCode,
Name: name,
In: in,
Value: format,
message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
}
}
// InvalidTypeName an error for when the type is invalid
func InvalidTypeName(typeName string) *Validation {
return &Validation{
code: InvalidTypeCode,
Value: typeName,
message: fmt.Sprintf(invalidType, typeName),
}
}
// InvalidType creates an error for when the type is invalid
func InvalidType(name, in, typeName string, value interface{}) *Validation {
var message string
if in != "" {
switch value.(type) {
case string:
message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
case error:
message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
default:
message = fmt.Sprintf(typeFail, name, in, typeName)
}
} else {
switch value.(type) {
case string:
message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
case error:
message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
default:
message = fmt.Sprintf(typeFailNoIn, name, typeName)
}
}
return &Validation{
code: InvalidTypeCode,
Name: name,
In: in,
Value: value,
message: message,
}
}
// DuplicateItems error for when an array contains duplicates
func DuplicateItems(name, in string) *Validation {
msg := fmt.Sprintf(uniqueFail, name, in)
if in == "" {
msg = fmt.Sprintf(uniqueFailNoIn, name)
}
return &Validation{
code: UniqueFailCode,
Name: name,
In: in,
message: msg,
}
}
// TooManyItems error for when an array contains too many items
func TooManyItems(name, in string, max int64) *Validation {
msg := fmt.Sprintf(maxItemsFail, name, in, max)
if in == "" {
msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
}
return &Validation{
code: MaxItemsFailCode,
Name: name,
In: in,
message: msg,
}
}
// TooFewItems error for when an array contains too few items
func TooFewItems(name, in string, min int64) *Validation {
msg := fmt.Sprintf(minItemsFail, name, in, min)
if in == "" {
msg = fmt.Sprintf(minItemsFailNoIn, name, min)
}
return &Validation{
code: MinItemsFailCode,
Name: name,
In: in,
message: msg,
}
}
// ExceedsMaximumInt error for when maxinum validation fails
func ExceedsMaximumInt(name, in string, max int64, exclusive bool) *Validation {
var message string
if in == "" {
m := maxIncFailNoIn
if exclusive {
m = maxExcFailNoIn
}
message = fmt.Sprintf(m, name, max)
} else {
m := maxIncFail
if exclusive {
m = maxExcFail
}
message = fmt.Sprintf(m, name, in, max)
}
return &Validation{
code: MaxFailCode,
Name: name,
In: in,
Value: max,
message: message,
}
}
// ExceedsMaximumUint error for when maxinum validation fails
func ExceedsMaximumUint(name, in string, max uint64, exclusive bool) *Validation {
var message string
if in == "" {
m := maxIncFailNoIn
if exclusive {
m = maxExcFailNoIn
}
message = fmt.Sprintf(m, name, max)
} else {
m := maxIncFail
if exclusive {
m = maxExcFail
}
message = fmt.Sprintf(m, name, in, max)
}
return &Validation{
code: MaxFailCode,
Name: name,
In: in,
Value: max,
message: message,
}
}
// ExceedsMaximum error for when maxinum validation fails
func ExceedsMaximum(name, in string, max float64, exclusive bool) *Validation {
var message string
if in == "" {
m := maxIncFailNoIn
if exclusive {
m = maxExcFailNoIn
}
message = fmt.Sprintf(m, name, max)
} else {
m := maxIncFail
if exclusive {
m = maxExcFail
}
message = fmt.Sprintf(m, name, in, max)
}
return &Validation{
code: MaxFailCode,
Name: name,
In: in,
Value: max,
message: message,
}
}
// ExceedsMinimumInt error for when maxinum validation fails
func ExceedsMinimumInt(name, in string, min int64, exclusive bool) *Validation {
var message string
if in == "" {
m := minIncFailNoIn
if exclusive {
m = minExcFailNoIn
}
message = fmt.Sprintf(m, name, min)
} else {
m := minIncFail
if exclusive {
m = minExcFail
}
message = fmt.Sprintf(m, name, in, min)
}
return &Validation{
code: MinFailCode,
Name: name,
In: in,
Value: min,
message: message,
}
}
// ExceedsMinimumUint error for when maxinum validation fails
func ExceedsMinimumUint(name, in string, min uint64, exclusive bool) *Validation {
var message string
if in == "" {
m := minIncFailNoIn
if exclusive {
m = minExcFailNoIn
}
message = fmt.Sprintf(m, name, min)
} else {
m := minIncFail
if exclusive {
m = minExcFail
}
message = fmt.Sprintf(m, name, in, min)
}
return &Validation{
code: MinFailCode,
Name: name,
In: in,
Value: min,
message: message,
}
}
// ExceedsMinimum error for when maxinum validation fails
func ExceedsMinimum(name, in string, min float64, exclusive bool) *Validation {
var message string
if in == "" {
m := minIncFailNoIn
if exclusive {
m = minExcFailNoIn
}
message = fmt.Sprintf(m, name, min)
} else {
m := minIncFail
if exclusive {
m = minExcFail
}
message = fmt.Sprintf(m, name, in, min)
}
return &Validation{
code: MinFailCode,
Name: name,
In: in,
Value: min,
message: message,
}
}
// NotMultipleOf error for when multiple of validation fails
func NotMultipleOf(name, in string, multiple interface{}) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(multipleOfFailNoIn, name, multiple)
} else {
msg = fmt.Sprintf(multipleOfFail, name, in, multiple)
}
return &Validation{
code: MultipleOfFailCode,
Name: name,
In: in,
Value: multiple,
message: msg,
}
}
// EnumFail error for when an enum validation fails
func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(enumFailNoIn, name, values)
} else {
msg = fmt.Sprintf(enumFail, name, in, values)
}
return &Validation{
code: EnumFailCode,
Name: name,
In: in,
Value: value,
Values: values,
message: msg,
}
}
// Required error for when a value is missing
func Required(name, in string) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(requiredFailNoIn, name)
} else {
msg = fmt.Sprintf(requiredFail, name, in)
}
return &Validation{
code: RequiredFailCode,
Name: name,
In: in,
message: msg,
}
}
// TooLong error for when a string is too long
func TooLong(name, in string, max int64) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
} else {
msg = fmt.Sprintf(tooLongMessage, name, in, max)
}
return &Validation{
code: TooLongFailCode,
Name: name,
In: in,
message: msg,
}
}
// TooShort error for when a string is too short
func TooShort(name, in string, min int64) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
} else {
msg = fmt.Sprintf(tooShortMessage, name, in, min)
}
return &Validation{
code: TooShortFailCode,
Name: name,
In: in,
message: msg,
}
}
// FailedPattern error for when a string fails a regex pattern match
// the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
func FailedPattern(name, in, pattern string) *Validation {
var msg string
if in == "" {
msg = fmt.Sprintf(patternFailNoIn, name, pattern)
} else {
msg = fmt.Sprintf(patternFail, name, in, pattern)
}
return &Validation{
code: PatternFailCode,
Name: name,
In: in,
message: msg,
}
}
// MultipleOfMustBePositive error for when a
// multipleOf factor is negative
func MultipleOfMustBePositive(name, in string, factor interface{}) *Validation {
return &Validation{
code: MultipleOfMustBePositiveCode,
Name: name,
In: in,
Value: factor,
message: fmt.Sprintf(multipleOfMustBePositive, name, factor),
}
}

View 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.

View File

@@ -0,0 +1,390 @@
// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// 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.
// author sigu-399
// author-github https://github.com/sigu-399
// author-mail sigu.399@gmail.com
//
// repository-name jsonpointer
// repository-desc An implementation of JSON Pointer - Go language
//
// description Main and unique file.
//
// created 25-02-2013
package jsonpointer
import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/go-openapi/swag"
)
const (
emptyPointer = ``
pointerSeparator = `/`
invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
)
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
// JSONPointable is an interface for structs to implement when they need to customize the
// json pointer process
type JSONPointable interface {
JSONLookup(string) (interface{}, error)
}
// JSONSetable is an interface for structs to implement when they need to customize the
// json pointer process
type JSONSetable interface {
JSONSet(string, interface{}) error
}
// New creates a new json pointer for the given string
func New(jsonPointerString string) (Pointer, error) {
var p Pointer
err := p.parse(jsonPointerString)
return p, err
}
// Pointer the json pointer reprsentation
type Pointer struct {
referenceTokens []string
}
// "Constructor", parses the given string JSON pointer
func (p *Pointer) parse(jsonPointerString string) error {
var err error
if jsonPointerString != emptyPointer {
if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
err = errors.New(invalidStart)
} else {
referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
for _, referenceToken := range referenceTokens[1:] {
p.referenceTokens = append(p.referenceTokens, referenceToken)
}
}
}
return err
}
// Get uses the pointer to retrieve a value from a JSON document
func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
return p.get(document, swag.DefaultJSONNameProvider)
}
// Set uses the pointer to set a value from a JSON document
func (p *Pointer) Set(document interface{}, value interface{}) (interface{}, error) {
return document, p.set(document, value, swag.DefaultJSONNameProvider)
}
// GetForToken gets a value for a json pointer token 1 level deep
func GetForToken(document interface{}, decodedToken string) (interface{}, reflect.Kind, error) {
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
}
// SetForToken gets a value for a json pointer token 1 level deep
func SetForToken(document interface{}, decodedToken string, value interface{}) (interface{}, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
}
func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
switch kind {
case reflect.Struct:
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return nil, kind, err
}
return r, kind, nil
}
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
return fld.Interface(), kind, nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if mv.IsValid() && !swag.IsZero(mv) {
return mv.Interface(), kind, nil
}
return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return nil, kind, err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
}
elem := rValue.Index(tokenIndex)
return elem.Interface(), kind, nil
default:
return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
}
}
func setSingleImpl(node, data interface{}, decodedToken string, nameProvider *swag.NameProvider) error {
rValue := reflect.Indirect(reflect.ValueOf(node))
switch rValue.Kind() {
case reflect.Struct:
if ns, ok := node.(JSONSetable); ok { // pointer impl
return ns.JSONSet(decodedToken, data)
}
if rValue.Type().Implements(jsonSetableType) {
return node.(JSONSetable).JSONSet(decodedToken, data)
}
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.IsValid() {
fld.Set(reflect.ValueOf(data))
}
return nil
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
rValue.SetMapIndex(kv, reflect.ValueOf(data))
return nil
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if !elem.CanSet() {
return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
}
elem.Set(reflect.ValueOf(data))
return nil
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interface{}, reflect.Kind, error) {
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
kind := reflect.Invalid
// Full document when empty
if len(p.referenceTokens) == 0 {
return node, kind, nil
}
for _, token := range p.referenceTokens {
decodedToken := Unescape(token)
r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
if err != nil {
return nil, knd, err
}
node, kind = r, knd
}
rValue := reflect.ValueOf(node)
kind = rValue.Kind()
return node, kind, nil
}
func (p *Pointer) set(node, data interface{}, nameProvider *swag.NameProvider) error {
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
return fmt.Errorf("only structs, pointers, maps and slices are supported for setting values")
}
if nameProvider == nil {
nameProvider = swag.DefaultJSONNameProvider
}
// Full document when empty
if len(p.referenceTokens) == 0 {
return nil
}
lastI := len(p.referenceTokens) - 1
for i, token := range p.referenceTokens {
isLastToken := i == lastI
decodedToken := Unescape(token)
if isLastToken {
return setSingleImpl(node, data, decodedToken, nameProvider)
}
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
switch kind {
case reflect.Struct:
if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
if err != nil {
return err
}
fld := reflect.ValueOf(r)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = r
continue
}
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
if !ok {
return fmt.Errorf("object has no field %q", decodedToken)
}
fld := rValue.FieldByName(nm)
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
node = fld.Addr().Interface()
continue
}
node = fld.Interface()
case reflect.Map:
kv := reflect.ValueOf(decodedToken)
mv := rValue.MapIndex(kv)
if !mv.IsValid() {
return fmt.Errorf("object has no key %q", decodedToken)
}
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
node = mv.Addr().Interface()
continue
}
node = mv.Interface()
case reflect.Slice:
tokenIndex, err := strconv.Atoi(decodedToken)
if err != nil {
return err
}
sLength := rValue.Len()
if tokenIndex < 0 || tokenIndex >= sLength {
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
}
elem := rValue.Index(tokenIndex)
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
node = elem.Addr().Interface()
continue
}
node = elem.Interface()
default:
return fmt.Errorf("invalid token reference %q", decodedToken)
}
}
return nil
}
// DecodedTokens returns the decoded tokens
func (p *Pointer) DecodedTokens() []string {
result := make([]string, 0, len(p.referenceTokens))
for _, t := range p.referenceTokens {
result = append(result, Unescape(t))
}
return result
}
// IsEmpty returns true if this is an empty json pointer
// this indicates that it points to the root document
func (p *Pointer) IsEmpty() bool {
return len(p.referenceTokens) == 0
}
// Pointer to string representation function
func (p *Pointer) String() string {
if len(p.referenceTokens) == 0 {
return emptyPointer
}
pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
return pointerString
}
// Specific JSON pointer encoding here
// ~0 => ~
// ~1 => /
// ... and vice versa
const (
encRefTok0 = `~0`
encRefTok1 = `~1`
decRefTok0 = `~`
decRefTok1 = `/`
)
// Unescape unescapes a json pointer reference token string to the original representation
func Unescape(token string) string {
step1 := strings.Replace(token, encRefTok1, decRefTok1, -1)
step2 := strings.Replace(step1, encRefTok0, decRefTok0, -1)
return step2
}
// Escape escapes a pointer reference token string
func Escape(token string) string {
step1 := strings.Replace(token, decRefTok0, encRefTok0, -1)
step2 := strings.Replace(step1, decRefTok1, encRefTok1, -1)
return step2
}

View 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.

View File

@@ -0,0 +1,156 @@
// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
//
// 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.
// author sigu-399
// author-github https://github.com/sigu-399
// author-mail sigu.399@gmail.com
//
// repository-name jsonreference
// repository-desc An implementation of JSON Reference - Go language
//
// description Main and unique file.
//
// created 26-02-2013
package jsonreference
import (
"errors"
"net/url"
"strings"
"github.com/PuerkitoBio/purell"
"github.com/go-openapi/jsonpointer"
)
const (
fragmentRune = `#`
)
// New creates a new reference for the given string
func New(jsonReferenceString string) (Ref, error) {
var r Ref
err := r.parse(jsonReferenceString)
return r, err
}
// MustCreateRef parses the ref string and panics when it's invalid.
// Use the New method for a version that returns an error
func MustCreateRef(ref string) Ref {
r, err := New(ref)
if err != nil {
panic(err)
}
return r
}
// Ref represents a json reference object
type Ref struct {
referenceURL *url.URL
referencePointer jsonpointer.Pointer
HasFullURL bool
HasURLPathOnly bool
HasFragmentOnly bool
HasFileScheme bool
HasFullFilePath bool
}
// GetURL gets the URL for this reference
func (r *Ref) GetURL() *url.URL {
return r.referenceURL
}
// GetPointer gets the json pointer for this reference
func (r *Ref) GetPointer() *jsonpointer.Pointer {
return &r.referencePointer
}
// String returns the best version of the url for this reference
func (r *Ref) String() string {
if r.referenceURL != nil {
return r.referenceURL.String()
}
if r.HasFragmentOnly {
return fragmentRune + r.referencePointer.String()
}
return r.referencePointer.String()
}
// IsRoot returns true if this reference is a root document
func (r *Ref) IsRoot() bool {
return r.referenceURL != nil &&
!r.IsCanonical() &&
!r.HasURLPathOnly &&
r.referenceURL.Fragment == ""
}
// IsCanonical returns true when this pointer starts with http(s):// or file://
func (r *Ref) IsCanonical() bool {
return (r.HasFileScheme && r.HasFullFilePath) || (!r.HasFileScheme && r.HasFullURL)
}
// "Constructor", parses the given string JSON reference
func (r *Ref) parse(jsonReferenceString string) error {
parsed, err := url.Parse(jsonReferenceString)
if err != nil {
return err
}
r.referenceURL, _ = url.Parse(purell.NormalizeURL(parsed, purell.FlagsSafe|purell.FlagRemoveDuplicateSlashes))
refURL := r.referenceURL
if refURL.Scheme != "" && refURL.Host != "" {
r.HasFullURL = true
} else {
if refURL.Path != "" {
r.HasURLPathOnly = true
} else if refURL.RawQuery == "" && refURL.Fragment != "" {
r.HasFragmentOnly = true
}
}
r.HasFileScheme = refURL.Scheme == "file"
r.HasFullFilePath = strings.HasPrefix(refURL.Path, "/")
// invalid json-pointer error means url has no json-pointer fragment. simply ignore error
r.referencePointer, _ = jsonpointer.New(refURL.Fragment)
return nil
}
// Inherits creates a new reference from a parent and a child
// If the child cannot inherit from the parent, an error is returned
func (r *Ref) Inherits(child Ref) (*Ref, error) {
childURL := child.GetURL()
parentURL := r.GetURL()
if childURL == nil {
return nil, errors.New("child url is nil")
}
if parentURL == nil {
return &child, nil
}
ref, err := New(parentURL.ResolveReference(childURL).String())
if err != nil {
return nil, err
}
return &ref, nil
}

202
src/runtime/vendor/github.com/go-openapi/loads/LICENSE generated vendored Normal file
View 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.

21
src/runtime/vendor/github.com/go-openapi/loads/doc.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
// 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 loads provides document loading methods for swagger (OAI) specifications.
It is used by other go-openapi packages to load and run analysis on local or remote spec documents.
*/
package loads

298
src/runtime/vendor/github.com/go-openapi/loads/spec.go generated vendored Normal file
View File

@@ -0,0 +1,298 @@
// 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 loads
import (
"bytes"
"encoding/gob"
"encoding/json"
"fmt"
"net/url"
"github.com/go-openapi/analysis"
"github.com/go-openapi/spec"
"github.com/go-openapi/swag"
)
// JSONDoc loads a json document from either a file or a remote url
func JSONDoc(path string) (json.RawMessage, error) {
data, err := swag.LoadFromFileOrHTTP(path)
if err != nil {
return nil, err
}
return json.RawMessage(data), nil
}
// DocLoader represents a doc loader type
type DocLoader func(string) (json.RawMessage, error)
// DocMatcher represents a predicate to check if a loader matches
type DocMatcher func(string) bool
var (
loaders *loader
defaultLoader *loader
)
func init() {
defaultLoader = &loader{Match: func(_ string) bool { return true }, Fn: JSONDoc}
loaders = defaultLoader
spec.PathLoader = loaders.Fn
AddLoader(swag.YAMLMatcher, swag.YAMLDoc)
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
//gob.Register(spec.Refable{})
}
// AddLoader for a document
func AddLoader(predicate DocMatcher, load DocLoader) {
prev := loaders
loaders = &loader{
Match: predicate,
Fn: load,
Next: prev,
}
spec.PathLoader = loaders.Fn
}
type loader struct {
Fn DocLoader
Match DocMatcher
Next *loader
}
// JSONSpec loads a spec from a json document
func JSONSpec(path string) (*Document, error) {
data, err := JSONDoc(path)
if err != nil {
return nil, err
}
// convert to json
return Analyzed(data, "")
}
// Document represents a swagger spec document
type Document struct {
// specAnalyzer
Analyzer *analysis.Spec
spec *spec.Swagger
specFilePath string
origSpec *spec.Swagger
schema *spec.Schema
raw json.RawMessage
}
// Embedded returns a Document based on embedded specs. No analysis is required
func Embedded(orig, flat json.RawMessage) (*Document, error) {
var origSpec, flatSpec spec.Swagger
if err := json.Unmarshal(orig, &origSpec); err != nil {
return nil, err
}
if err := json.Unmarshal(flat, &flatSpec); err != nil {
return nil, err
}
return &Document{
raw: orig,
origSpec: &origSpec,
spec: &flatSpec,
}, nil
}
// Spec loads a new spec document
func Spec(path string) (*Document, error) {
specURL, err := url.Parse(path)
if err != nil {
return nil, err
}
var lastErr error
for l := loaders.Next; l != nil; l = l.Next {
if loaders.Match(specURL.Path) {
b, err2 := loaders.Fn(path)
if err2 != nil {
lastErr = err2
continue
}
doc, err3 := Analyzed(b, "")
if err3 != nil {
return nil, err3
}
if doc != nil {
doc.specFilePath = path
}
return doc, nil
}
}
if lastErr != nil {
return nil, lastErr
}
b, err := defaultLoader.Fn(path)
if err != nil {
return nil, err
}
document, err := Analyzed(b, "")
if document != nil {
document.specFilePath = path
}
return document, err
}
// Analyzed creates a new analyzed spec document
func Analyzed(data json.RawMessage, version string) (*Document, error) {
if version == "" {
version = "2.0"
}
if version != "2.0" {
return nil, fmt.Errorf("spec version %q is not supported", version)
}
raw := data
trimmed := bytes.TrimSpace(data)
if len(trimmed) > 0 {
if trimmed[0] != '{' && trimmed[0] != '[' {
yml, err := swag.BytesToYAMLDoc(trimmed)
if err != nil {
return nil, fmt.Errorf("analyzed: %v", err)
}
d, err := swag.YAMLToJSON(yml)
if err != nil {
return nil, fmt.Errorf("analyzed: %v", err)
}
raw = d
}
}
swspec := new(spec.Swagger)
if err := json.Unmarshal(raw, swspec); err != nil {
return nil, err
}
origsqspec, err := cloneSpec(swspec)
if err != nil {
return nil, err
}
d := &Document{
Analyzer: analysis.New(swspec),
schema: spec.MustLoadSwagger20Schema(),
spec: swspec,
raw: raw,
origSpec: origsqspec,
}
return d, nil
}
// Expanded expands the ref fields in the spec document and returns a new spec document
func (d *Document) Expanded(options ...*spec.ExpandOptions) (*Document, error) {
swspec := new(spec.Swagger)
if err := json.Unmarshal(d.raw, swspec); err != nil {
return nil, err
}
var expandOptions *spec.ExpandOptions
if len(options) > 0 {
expandOptions = options[0]
} else {
expandOptions = &spec.ExpandOptions{
RelativeBase: d.specFilePath,
}
}
if err := spec.ExpandSpec(swspec, expandOptions); err != nil {
return nil, err
}
dd := &Document{
Analyzer: analysis.New(swspec),
spec: swspec,
specFilePath: d.specFilePath,
schema: spec.MustLoadSwagger20Schema(),
raw: d.raw,
origSpec: d.origSpec,
}
return dd, nil
}
// BasePath the base path for this spec
func (d *Document) BasePath() string {
return d.spec.BasePath
}
// Version returns the version of this spec
func (d *Document) Version() string {
return d.spec.Swagger
}
// Schema returns the swagger 2.0 schema
func (d *Document) Schema() *spec.Schema {
return d.schema
}
// Spec returns the swagger spec object model
func (d *Document) Spec() *spec.Swagger {
return d.spec
}
// Host returns the host for the API
func (d *Document) Host() string {
return d.spec.Host
}
// Raw returns the raw swagger spec as json bytes
func (d *Document) Raw() json.RawMessage {
return d.raw
}
// OrigSpec yields the original spec
func (d *Document) OrigSpec() *spec.Swagger {
return d.origSpec
}
// ResetDefinitions gives a shallow copy with the models reset
func (d *Document) ResetDefinitions() *Document {
defs := make(map[string]spec.Schema, len(d.origSpec.Definitions))
for k, v := range d.origSpec.Definitions {
defs[k] = v
}
d.spec.Definitions = defs
return d
}
// Pristine creates a new pristine document instance based on the input data
func (d *Document) Pristine() *Document {
dd, _ := Analyzed(d.Raw(), d.Version())
return dd
}
// SpecFilePath returns the file path of the spec if one is defined
func (d *Document) SpecFilePath() string {
return d.specFilePath
}
func cloneSpec(src *spec.Swagger) (*spec.Swagger, error) {
var b bytes.Buffer
if err := gob.NewEncoder(&b).Encode(src); err != nil {
return nil, err
}
var dst spec.Swagger
if err := gob.NewDecoder(&b).Decode(&dst); err != nil {
return nil, err
}
return &dst, nil
}

View 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.

View File

@@ -0,0 +1,151 @@
// 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 consmer for byte streams,
// takes a Writer/BinaryUnmarshaler interface or binary slice by reference,
// and reads from the provided reader
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
}
close := defaultCloser
if vals.Close {
if cl, ok := reader.(io.Closer); ok {
close = cl.Close
}
}
defer close()
if wrtr, ok := data.(io.Writer); ok {
_, err := io.Copy(wrtr, reader)
return err
}
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(reader)
if err != nil {
return err
}
b := buf.Bytes()
if bu, ok := data.(encoding.BinaryUnmarshaler); ok {
return bu.UnmarshalBinary(b)
}
if t := reflect.TypeOf(data); data != nil && t.Kind() == reflect.Ptr {
v := reflect.Indirect(reflect.ValueOf(data))
if t = v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
v.SetBytes(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,
// takes a Reader/BinaryMarshaler interface or binary slice,
// and writes to a writer (essentially a pipe)
func ByteStreamProducer(opts ...byteStreamOpt) Producer {
var vals byteStreamOpts
for _, opt := range opts {
opt(&vals)
}
return ProducerFunc(func(writer io.Writer, data interface{}) error {
if writer == nil {
return errors.New("ByteStreamProducer requires a writer") // early exit
}
close := defaultCloser
if vals.Close {
if cl, ok := writer.(io.Closer); ok {
close = cl.Close
}
}
defer close()
if rdr, ok := data.(io.Reader); ok {
_, err := io.Copy(writer, rdr)
return err
}
if bm, ok := data.(encoding.BinaryMarshaler); ok {
bytes, err := bm.MarshalBinary()
if err != nil {
return err
}
_, err = writer.Write(bytes)
return err
}
if data != nil {
if e, ok := data.(error); ok {
_, err := writer.Write([]byte(e.Error()))
return err
}
v := reflect.Indirect(reflect.ValueOf(data))
if t := v.Type(); t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
_, err := writer.Write(v.Bytes())
return err
}
if t := v.Type(); t.Kind() == reflect.Struct || t.Kind() == reflect.Slice {
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")
})
}

View File

@@ -0,0 +1,60 @@
// 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/runtime"
"github.com/go-openapi/strfmt"
)
// 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("Authorization", "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("Authorization", "Bearer "+token)
})
}

View File

@@ -0,0 +1,53 @@
package client
import (
"io"
"io/ioutil"
"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 {
//#nosec
io.Copy(ioutil.Discard, d.rdr)
}
return d.rdr.Close()
}

View File

@@ -0,0 +1,374 @@
// 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"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/go-openapi/runtime"
"github.com/go-openapi/strfmt"
)
// NewRequest creates a new swagger http client request
func newRequest(method, pathPattern string, writer runtime.ClientRequestWriter) (*request, error) {
return &request{
pathPattern: pathPattern,
method: method,
writer: writer,
header: make(http.Header),
query: make(url.Values),
timeout: DefaultTimeout,
}, nil
}
// 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
}
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 (r *request) buildHTTP(mediaType, basePath string, producers map[string]runtime.Producer, registry strfmt.Registry, auth runtime.ClientAuthInfoWriter) (*http.Request, error) {
// build the data
if err := r.writer.WriteToRequest(r, registry); err != nil {
return nil, err
}
if auth != nil {
if err := auth.AuthenticateRequest(r, registry); err != nil {
return nil, err
}
}
// create http request
var reinstateSlash bool
if r.pathPattern != "" && r.pathPattern != "/" && r.pathPattern[len(r.pathPattern)-1] == '/' {
reinstateSlash = true
}
urlPath := path.Join(basePath, r.pathPattern)
for k, v := range r.pathParams {
urlPath = strings.Replace(urlPath, "{"+k+"}", url.PathEscape(v), -1)
}
if reinstateSlash {
urlPath = urlPath + "/"
}
var body io.ReadCloser
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 = ioutil.NopCloser(r.buf)
if r.isMultipart(mediaType) {
pr, pw = io.Pipe()
body = pr
}
}
req, err := http.NewRequest(r.method, urlPath, body)
if err != nil {
return nil, err
}
req.URL.RawQuery = r.query.Encode()
req.Header = r.header
// check if this is a form type request
if len(r.formFields) > 0 || len(r.fileFields) > 0 {
if !r.isMultipart(mediaType) {
req.Header.Set(runtime.HeaderContentType, mediaType)
formString := r.formFields.Encode()
// set content length before writing to the buffer
req.ContentLength = int64(len(formString))
// write the form values as the body
r.buf.WriteString(formString)
return req, nil
}
mp := multipart.NewWriter(pw)
req.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 {
pw.CloseWithError(err)
log.Println(err)
}
}
}
defer func() {
for _, ff := range r.fileFields {
for _, ffi := range ff {
ffi.Close()
}
}
}()
for fn, f := range r.fileFields {
for _, fi := range f {
wrtr, err := mp.CreateFormFile(fn, filepath.Base(fi.Name()))
if err != nil {
pw.CloseWithError(err)
log.Println(err)
} else if _, err := io.Copy(wrtr, fi); err != nil {
pw.CloseWithError(err)
log.Println(err)
}
}
}
}()
return req, nil
}
// 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
req.Header.Set(runtime.HeaderContentType, mediaType)
if rdr, ok := r.payload.(io.ReadCloser); ok {
req.Body = rdr
return req, nil
}
if rdr, ok := r.payload.(io.Reader); ok {
req.Body = ioutil.NopCloser(rdr)
return req, nil
}
req.GetBody = func() (io.ReadCloser, error) {
var b bytes.Buffer
producer := producers[mediaType]
if err := producer.Produce(&b, r.payload); err != nil {
return nil, err
}
if _, err := r.buf.Write(b.Bytes()); err != nil {
return nil, err
}
return ioutil.NopCloser(&b), nil
}
// set the content length of the request or else a chunked transfer is
// declared, and this corrupts outgoing JSON payloads. the content's
// length must be set prior to the body being written per the spec at
// https://golang.org/pkg/net/http
//
// If Body is present, Content-Length is <= 0 and TransferEncoding
// hasn't been set to "identity", Write adds
// "Transfer-Encoding: chunked" to the header. Body is closed
// after it is sent.
//
// to that end a temporary buffer, b, is created to produce the payload
// body, and then its size is used to set the request's content length
var b bytes.Buffer
producer := producers[mediaType]
if err := producer.Produce(&b, r.payload); err != nil {
return nil, err
}
req.ContentLength = int64(b.Len())
if _, err := r.buf.Write(b.Bytes()); err != nil {
return nil, err
}
}
if runtime.CanHaveBody(req.Method) && req.Body == nil && req.Header.Get(runtime.HeaderContentType) == "" {
req.Header.Set(runtime.HeaderContentType, mediaType)
}
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.Replace(path, "{"+k+"}", v, -1)
}
return path
}
func (r *request) GetBody() []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
}
// 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
}

View File

@@ -0,0 +1,44 @@
// 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{}
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) Body() io.ReadCloser {
return r.resp.Body
}

View File

@@ -0,0 +1,437 @@
// 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"
"fmt"
"io/ioutil"
"mime"
"net/http"
"net/http/httputil"
"strings"
"sync"
"time"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
)
// 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
// 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 false, any certificate is accepted.
InsecureSkipVerify bool
// 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{}
// 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, fmt.Errorf("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
// 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
if opts.LoadedCA != nil {
caCertPool := x509.NewCertPool()
caCertPool.AddCert(opts.LoadedCA)
cfg.RootCAs = caCertPool
} else if opts.CA != "" {
// load ca cert
caCert, err := ioutil.ReadFile(opts.CA)
if err != nil {
return nil, fmt.Errorf("tls client ca: %v", err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
cfg.RootCAs = caCertPool
}
// apply servername overrride
if opts.ServerName != "" {
cfg.InsecureSkipVerify = false
cfg.ServerName = opts.ServerName
}
cfg.BuildNameToCertificate()
return cfg, nil
}
// 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
Debug bool
logger logger.Logger
clientOnce *sync.Once
client *http.Client
schemes []string
}
// 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.JSONMime: runtime.JSONConsumer(),
runtime.XMLMime: runtime.XMLConsumer(),
runtime.TextMime: runtime.TextConsumer(),
runtime.HTMLMime: runtime.TextConsumer(),
runtime.DefaultMime: runtime.ByteStreamConsumer(),
}
rt.Producers = map[string]runtime.Producer{
runtime.JSONMime: runtime.JSONProducer(),
runtime.XMLMime: runtime.XMLProducer(),
runtime.TextMime: runtime.TextProducer(),
runtime.HTMLMime: runtime.TextProducer(),
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{}
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
}
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 "http"
}
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 != "https" && schLen > 1 {
for _, sch := range schemes {
if sch == "https" {
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),
),
)
}
// 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) {
params, readResponse, auth := operation.Params, operation.Reader, operation.AuthInfo
request, err := newRequest(operation.Method, operation.PathPattern, params)
if err != nil {
return nil, err
}
var accept []string
accept = append(accept, operation.ProducesMediaTypes...)
if err = request.SetHeaderParam(runtime.HeaderAccept, accept...); err != nil {
return nil, err
}
if auth == nil && r.DefaultAuthentication != nil {
auth = r.DefaultAuthentication
}
//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, 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, err
}
req.URL.Scheme = r.pickScheme(operation.Schemes)
req.URL.Host = r.Host
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 hasTimeout bool
pctx := operation.Context
if pctx == nil {
pctx = r.Context
} else {
hasTimeout = true
}
if pctx == nil {
pctx = context.Background()
}
var ctx context.Context
var cancel context.CancelFunc
if hasTimeout {
ctx, cancel = context.WithCancel(pctx)
} else {
ctx, cancel = context.WithTimeout(pctx, request.timeout)
}
defer cancel()
client := operation.Client
if client == nil {
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()
if r.Debug {
b, err2 := httputil.DumpResponse(res, true)
if err2 != nil {
return nil, err2
}
r.logger.Debugf("%s\n", string(b))
}
ct := res.Header.Get(runtime.HeaderContentType)
if ct == "" { // this should really really never occur
ct = r.DefaultMediaType
}
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(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
}

View 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
}

View 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
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)
}

View File

@@ -0,0 +1,100 @@
// 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"
"io/ioutil"
"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 {
SetHeaderParam(string, ...string) error
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 = ioutil.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
}

View 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 runtime
import (
"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
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 (a *APIError) Error() string {
return fmt.Sprintf("%s (status %d): %+v ", a.OperationName, a.Code, a.Response)
}

View 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
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"
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"
// MultipartFormMime the multipart form mime type
MultipartFormMime = "multipart/form-data"
// URLencodedFormMime the url encoded form mime type
URLencodedFormMime = "application/x-www-form-urlencoded"
)

View 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 })

View File

@@ -0,0 +1,33 @@
// 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/multipart"
// File represents an uploaded file.
type File struct {
Data multipart.File
Header *multipart.FileHeader
}
// Read bytes from the file
func (f *File) Read(p []byte) (n int, err error) {
return f.Data.Read(p)
}
// Close the file
func (f *File) Close() error {
return f.Data.Close()
}

View 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
}

View File

@@ -0,0 +1,103 @@
// 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"
"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
}

View 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)
})
}

View File

@@ -0,0 +1,12 @@
package logger
import "os"
type Logger interface {
Printf(format string, args ...interface{})
Debugf(format string, args ...interface{})
}
func DebugEnabled() bool {
return os.Getenv("SWAGGER_DEBUG") != "" || os.Getenv("DEBUG") != ""
}

View File

@@ -0,0 +1,22 @@
package logger
import (
"fmt"
"os"
)
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...)
}

View File

@@ -0,0 +1,582 @@
// 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"
"net/http"
"strings"
"sync"
"github.com/go-openapi/analysis"
"github.com/go-openapi/errors"
"github.com/go-openapi/loads"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/logger"
"github.com/go-openapi/runtime/middleware/untyped"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
)
// Debug when true turns on verbose logging
var Debug = logger.DebugEnabled()
var Logger logger.Logger = logger.StandardLogger{}
func debugLog(format string, args ...interface{}) {
if Debug {
Logger.Printf(format, args...)
}
}
// 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
}
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(operationID 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
func NewRoutableContext(spec *loads.Document, routableAPI RoutableAPI, routes Router) *Context {
var an *analysis.Spec
if spec != nil {
an = analysis.New(spec.Spec())
}
ctx := &Context{spec: spec, api: routableAPI, analyzer: an, router: routes}
return ctx
}
// NewContext creates a new context wrapper
func NewContext(spec *loads.Document, api *untyped.API, routes Router) *Context {
var an *analysis.Spec
if spec != nil {
an = analysis.New(spec.Spec())
}
ctx := &Context{spec: spec, analyzer: an}
ctx.api = newRoutableUntypedAPI(spec, api, ctx)
ctx.router = routes
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()
}
// 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
requestContentType := "*/*"
// 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 {
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 && runtime.HasBody(request) {
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 {
debugLog("[%s %s] found response format %q in context", r.Method, r.URL.Path, v)
return v, r
}
format := NegotiateContentType(r, offers, "")
if format != "" {
debugLog("[%s %s] set response format %q in context", r.Method, r.URL.Path, format)
r = r.WithContext(stdContext.WithValue(rCtx, ctxResponseFormat, format))
}
debugLog("[%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 {
return nil, nil, errors.New(http.StatusForbidden, err.Error())
}
}
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 {
debugLog("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...)
}
debugLog("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{}) {
debugLog("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())
debugLog("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
prod, ok := producers[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, "can't find a producer for "+format))
}
prod = pr
}
resp.WriteResponse(rw, prod)
return
}
if err, ok := data.(error); ok {
if format == "" {
rw.Header().Set(runtime.HeaderContentType, runtime.JSONMime)
}
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(200)
if r.Method == "HEAD" {
return
}
producers := c.api.ProducersFor(normalizeOffers(offers))
prod, ok := producers[format]
if !ok {
panic(errors.New(http.StatusInternalServerError, "can't find a producer for "+format))
}
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 == 204 || r.Method == "HEAD" {
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, "can't find a producer for "+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"))
}
// APIHandler returns a handler to serve the API, this includes a swagger spec, router and the contract defined in the swagger spec
func (c *Context) APIHandler(builder Builder) http.Handler {
b := builder
if b == nil {
b = PassthroughBuilder
}
var title string
sp := c.spec.Spec()
if sp != nil && sp.Info != nil && sp.Info.Title != "" {
title = sp.Info.Title
}
redocOpts := RedocOpts{
BasePath: c.BasePath(),
Title: title,
}
return Spec("", c.spec.Raw(), Redoc(redocOpts, c.RoutesHandler(b)))
}
// 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)))
}

View 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.

View File

@@ -0,0 +1,452 @@
// Package denco provides fast URL router.
package denco
import (
"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 = '#'
// MaxSize is max size of records and internal slice.
MaxSize = (1 << 22) - 1
)
// Router represents a URL router.
type Router struct {
// SizeHint expects the maximum number of path parameters in records to Build.
// SizeHint will be used to determine the capacity of the memory to allocate.
// By default, SizeHint will be determined from given records to Build.
SizeHint int
static map[string]interface{}
param *doubleArray
}
// New returns a new Router.
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 fmt.Errorf("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&paramTypeSingle == paramTypeSingle
}
func (bc baseCheck) IsWildcardParam() bool {
return bc&paramTypeWildcard == paramTypeWildcard
}
func (bc baseCheck) IsAnyParam() bool {
return bc&paramTypeAny != 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() {
idx := nextIndex(da.bc[idx].Base(), ParamCharacter)
if idx >= len(da.bc) {
break
}
next := NextSeparator(path, i)
params := append(params, Param{Value: path[i:next]})
if nd, params, found := da.lookup(path[next:], params, idx); found {
return nd, params, true
}
}
if da.bc[idx].IsWildcardParam() {
idx := nextIndex(da.bc[idx].Base(), WildcardCharacter)
params := append(params, Param{Value: path[i:]})
return da.node[da.bc[idx].Base()], params, true
}
}
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, fmt.Errorf("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, fmt.Errorf("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) {
spChars := string([]byte{ParamCharacter, WildcardCharacter})
termChar := string(TerminationCharacter)
for _, r := range srcs {
if strings.ContainsAny(r.Key, spChars) {
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]
}

View 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)
}

View 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
}

View File

@@ -0,0 +1,62 @@
// 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

View File

@@ -0,0 +1,9 @@
// +build go1.8
package middleware
import "net/url"
func pathUnescape(path string) (string, error) {
return url.PathUnescape(path)
}

View File

@@ -0,0 +1,326 @@
// 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) (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
}
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 = 0
case s[0] == '1':
q = 1
default:
return -1, ""
}
s = s[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 + 1; 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 "", ""
}

View 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]
}

View File

@@ -0,0 +1,48 @@
// 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 {
panic(err)
}
}
// NotImplemented the error response when the response is not implemented
func NotImplemented(message string) Responder {
return &errorResp{http.StatusNotImplemented, message, make(http.Header)}
}

View 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)
})
}

View File

@@ -0,0 +1,480 @@
// 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/runtime"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/validate"
)
const defaultMaxMemory = 32 << 20
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 = &param
binder.formats = formats
if param.In != "body" {
binder.validator = validate.NewParamValidator(&param, 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 "string":
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 "array":
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 == "array" {
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 {
return errors.NewParseError(p.Name, p.parameter.In, "", ffErr)
}
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 == "array" {
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 {
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)
}
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() {
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)
}
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
}

View File

@@ -0,0 +1,9 @@
// +build !go1.8
package middleware
import "net/url"
func pathUnescape(path string) (string, error) {
return url.QueryUnescape(path)
}

View File

@@ -0,0 +1,101 @@
package middleware
import (
"bytes"
"fmt"
"html/template"
"net/http"
"path"
)
// RedocOpts configures the Redoc middlewares
type RedocOpts struct {
// BasePath for the UI path, defaults to: /
BasePath string
// Path combines with BasePath for the full UI path, defaults to: docs
Path string
// SpecURL the url to find the spec for
SpecURL string
// RedocURL for the js that generates the redoc site, defaults to: https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js
RedocURL string
// Title for the documentation site, default to: API documentation
Title string
}
// EnsureDefaults in case some options are missing
func (r *RedocOpts) EnsureDefaults() {
if r.BasePath == "" {
r.BasePath = "/"
}
if r.Path == "" {
r.Path = "docs"
}
if r.SpecURL == "" {
r.SpecURL = "/swagger.json"
}
if r.RedocURL == "" {
r.RedocURL = redocLatest
}
if r.Title == "" {
r.Title = "API documentation"
}
}
// 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(redocTemplate))
buf := bytes.NewBuffer(nil)
_ = tmpl.Execute(buf, opts)
b := buf.Bytes()
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if r.URL.Path == pth {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write(b)
return
}
if next == nil {
rw.Header().Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusNotFound)
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
return
}
next.ServeHTTP(rw, r)
})
}
const (
redocLatest = "https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"
redocTemplate = `<!DOCTYPE html>
<html>
<head>
<title>{{ .Title }}</title>
<!-- needed for adaptive design -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--
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>
`
)

View File

@@ -0,0 +1,104 @@
// 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/spec"
"github.com/go-openapi/strfmt"
)
// RequestBinder 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
}
// NewRequestBinder 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,
}
}
// 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
debugLog("binding %d parameters for %s %s", len(o.Parameters), request.Method, request.URL.EscapedPath())
for fieldName, param := range o.Parameters {
binder := o.paramBinders[fieldName]
debugLog("binding parameter %s for %s %s", fieldName, request.Method, request.URL.EscapedPath())
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("array") {
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
}

View File

@@ -0,0 +1,478 @@
// 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"
fpath "path"
"regexp"
"strings"
"github.com/go-openapi/runtime/security"
"github.com/go-openapi/analysis"
"github.com/go-openapi/errors"
"github.com/go-openapi/loads"
"github.com/go-openapi/runtime"
"github.com/go-openapi/runtime/middleware/denco"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
)
// 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)
}
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
}
type defaultRouter struct {
spec *loads.Document
routers map[string]*denco.Router
}
func newDefaultRouteBuilder(spec *loads.Document, api RoutableAPI) *defaultRouteBuilder {
return &defaultRouteBuilder{
spec: spec,
analyzer: analysis.New(spec.Spec()),
api: api,
records: make(map[string][]denco.Record),
}
}
// DefaultRouter creates a default implemenation of the router
func DefaultRouter(spec *loads.Document, api RoutableAPI) Router {
builder := newDefaultRouteBuilder(spec, api)
if spec != nil {
for method, paths := range builder.analyzer.Operations() {
for path, operation := range paths {
fp := fpath.Join(spec.BasePath(), path)
debugLog("adding route %s %s %q", method, fp, operation.ID)
builder.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)
debugLog("looking up route for %s %s", method, path)
if Debug {
if len(d.routers) == 0 {
debugLog("there are no known routers")
}
for meth := range d.routers {
debugLog("got a router for %s", meth)
}
}
if router, ok := d.routers[mth]; ok {
if m, rp, ok := router.Lookup(fpath.Clean(path)); ok && m != nil {
if entry, ok := m.(*routeEntry); ok {
debugLog("found a route for %s %s with %d parameters", method, path, len(entry.Parameters))
var params RouteParams
for _, p := range rp {
v, err := pathUnescape(p.Value)
if err != nil {
debugLog("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 {
debugLog("couldn't find a route by path for %s %s", method, path)
}
} else {
debugLog("couldn't find a route by method for %s %s", method, path)
}
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
}
// 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]
}
debugLog("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))
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: newUntypedRequestBinder(parameters, d.spec.Spec(), d.api.Formats()),
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)
var auths []RouteAuthenticator
for _, reqs := range requirements {
var schemes []string
scopes := make(map[string][]string, len(reqs))
var scopeSlices [][]string
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,
}
}

View 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)
})
}

View File

@@ -0,0 +1,48 @@
// 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"
)
// Spec creates a middleware to serve a swagger spec.
// This allows for altering the spec before starting the http listener.
// This can be useful if you want to serve the swagger spec from another path than /swagger.json
//
func Spec(basePath string, b []byte, next http.Handler) http.Handler {
if basePath == "" {
basePath = "/"
}
pth := path.Join(basePath, "swagger.json")
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
if r.URL.Path == pth {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusOK)
//#nosec
rw.Write(b)
return
}
if next == nil {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusNotFound)
return
}
next.ServeHTTP(rw, r)
})
}

View File

@@ -0,0 +1,286 @@
// 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/runtime"
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
)
// 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
}
// AuthorizersFor 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 {
var consumes []string
for k := range d.consumers {
consumes = append(consumes, k)
}
var produces []string
for k := range d.producers {
produces = append(produces, k)
}
var authenticators []string
for k := range d.authenticators {
authenticators = append(authenticators, k)
}
var operations []string
for m, v := range d.operations {
for p := range v {
operations = append(operations, fmt.Sprintf("%s %s", strings.ToUpper(m), p))
}
}
var definedAuths []string
for k := range d.spec.Spec().SecurityDefinitions {
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.Sort(sort.StringSlice(registrations))
sort.Sort(sort.StringSlice(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)
}
var unregistered []string
for k := range expected {
unregistered = append(unregistered, k)
}
sort.Sort(sort.StringSlice(unspecified))
sort.Sort(sort.StringSlice(unregistered))
if len(unregistered) > 0 || len(unspecified) > 0 {
return &errors.APIVerificationFailed{
Section: name,
MissingSpecification: unspecified,
MissingRegistration: unregistered,
}
}
return nil
}

View File

@@ -0,0 +1,122 @@
// 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/runtime"
"github.com/go-openapi/swag"
)
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 {
debugLog("validating content type for %q against [%s]", actual, strings.Join(allowed, ", "))
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 {
debugLog("validating request %s %s", request.Method, request.URL.EscapedPath())
validate := &validation{
context: ctx,
request: request,
route: route,
bound: make(map[string]interface{}),
}
validate.contentType()
if len(validate.result) == 0 {
validate.responseFormat()
}
if len(validate.result) == 0 {
validate.parameters()
}
return validate
}
func (v *validation) parameters() {
debugLog("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) {
debugLog("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 {
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 str, rCtx := v.context.ResponseFormat(v.request, v.route.Produces); str == "" && runtime.HasBody(v.request) {
v.request = rCtx
v.result = append(v.result, errors.InvalidResponseFormat(v.request.Header.Get(runtime.HeaderAccept), v.route.Produces))
}
}

View 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 runtime
import (
"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 {
return len(r.TransferEncoding) > 0 || r.ContentLength > 0
}
// JSONRequest creates a new http request with json headers set
func JSONRequest(method, urlStr string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequest(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)
}

View File

@@ -0,0 +1,215 @@
// 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"
)
// HttpAuthenticator is a function that authenticates a HTTP request
func HttpAuthenticator(handler func(*http.Request) (bool, interface{}, error)) runtime.Authenticator {
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)
// BasicAuth creates a basic auth authenticator with the provided authentication function
func BasicAuth(authenticate UserPassAuthentication) runtime.Authenticator {
return HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
if usr, pass, ok := r.BasicAuth(); ok {
p, err := authenticate(usr, pass)
return true, p, err
}
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 HttpAuthenticator(func(r *http.Request) (bool, interface{}, error) {
if usr, pass, ok := r.BasicAuth(); ok {
ctx, p, err := authenticate(r.Context(), usr, pass)
*r = *r.WithContext(ctx)
return true, p, err
}
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("Authorization")
if strings.HasPrefix(hdr, prefix) {
token = strings.TrimPrefix(hdr, prefix)
}
if token == "" {
qs := r.Request.URL.Query()
token = qs.Get("access_token")
}
//#nosec
ct, _, _ := runtime.ContentType(r.Request.Header)
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
token = r.Request.FormValue("access_token")
}
if token == "" {
return false, nil, nil
}
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("Authorization")
if strings.HasPrefix(hdr, prefix) {
token = strings.TrimPrefix(hdr, prefix)
}
if token == "" {
qs := r.Request.URL.Query()
token = qs.Get("access_token")
}
//#nosec
ct, _, _ := runtime.ContentType(r.Request.Header)
if token == "" && (ct == "application/x-www-form-urlencoded" || ct == "multipart/form-data") {
token = r.Request.FormValue("access_token")
}
if token == "" {
return false, nil, nil
}
ctx, p, err := authenticate(r.Request.Context(), token, r.RequiredScopes)
*r.Request = *r.Request.WithContext(ctx)
return true, p, err
})
}

View 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 })
}

View 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",
}

View File

@@ -0,0 +1,111 @@
// 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 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
})
}

View 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
}

View 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)
})
}

202
src/runtime/vendor/github.com/go-openapi/spec/LICENSE generated vendored Normal file
View 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.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,24 @@
// 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 spec
// ContactInfo contact information for the exposed API.
//
// For more information: http://goo.gl/8us55a#contactObject
type ContactInfo struct {
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
Email string `json:"email,omitempty"`
}

47
src/runtime/vendor/github.com/go-openapi/spec/debug.go generated vendored Normal file
View File

@@ -0,0 +1,47 @@
// 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 spec
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
)
var (
// Debug is true when the SWAGGER_DEBUG env var is not empty.
// It enables a more verbose logging of validators.
Debug = os.Getenv("SWAGGER_DEBUG") != ""
// validateLogger is a debug logger for this package
specLogger *log.Logger
)
func init() {
debugOptions()
}
func debugOptions() {
specLogger = log.New(os.Stdout, "spec:", log.LstdFlags)
}
func debugLog(msg string, args ...interface{}) {
// A private, trivial trace logger, based on go-openapi/spec/expander.go:debugLog()
if Debug {
_, file1, pos1, _ := runtime.Caller(1)
specLogger.Printf("%s:%d: %s", filepath.Base(file1), pos1, fmt.Sprintf(msg, args...))
}
}

1227
src/runtime/vendor/github.com/go-openapi/spec/expander.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
// 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 spec
// ExternalDocumentation allows referencing an external resource for
// extended documentation.
//
// For more information: http://goo.gl/8us55a#externalDocumentationObject
type ExternalDocumentation struct {
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
}

193
src/runtime/vendor/github.com/go-openapi/spec/header.go generated vendored Normal file
View File

@@ -0,0 +1,193 @@
// 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 spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// HeaderProps describes a response header
type HeaderProps struct {
Description string `json:"description,omitempty"`
}
// Header describes a header for a response of the API
//
// For more information: http://goo.gl/8us55a#headerObject
type Header struct {
CommonValidations
SimpleSchema
VendorExtensible
HeaderProps
}
// ResponseHeader creates a new header instance for use in a response
func ResponseHeader() *Header {
return new(Header)
}
// WithDescription sets the description on this response, allows for chaining
func (h *Header) WithDescription(description string) *Header {
h.Description = description
return h
}
// Typed a fluent builder method for the type of parameter
func (h *Header) Typed(tpe, format string) *Header {
h.Type = tpe
h.Format = format
return h
}
// CollectionOf a fluent builder method for an array item
func (h *Header) CollectionOf(items *Items, format string) *Header {
h.Type = "array"
h.Items = items
h.CollectionFormat = format
return h
}
// WithDefault sets the default value on this item
func (h *Header) WithDefault(defaultValue interface{}) *Header {
h.Default = defaultValue
return h
}
// WithMaxLength sets a max length value
func (h *Header) WithMaxLength(max int64) *Header {
h.MaxLength = &max
return h
}
// WithMinLength sets a min length value
func (h *Header) WithMinLength(min int64) *Header {
h.MinLength = &min
return h
}
// WithPattern sets a pattern value
func (h *Header) WithPattern(pattern string) *Header {
h.Pattern = pattern
return h
}
// WithMultipleOf sets a multiple of value
func (h *Header) WithMultipleOf(number float64) *Header {
h.MultipleOf = &number
return h
}
// WithMaximum sets a maximum number value
func (h *Header) WithMaximum(max float64, exclusive bool) *Header {
h.Maximum = &max
h.ExclusiveMaximum = exclusive
return h
}
// WithMinimum sets a minimum number value
func (h *Header) WithMinimum(min float64, exclusive bool) *Header {
h.Minimum = &min
h.ExclusiveMinimum = exclusive
return h
}
// WithEnum sets a the enum values (replace)
func (h *Header) WithEnum(values ...interface{}) *Header {
h.Enum = append([]interface{}{}, values...)
return h
}
// WithMaxItems sets the max items
func (h *Header) WithMaxItems(size int64) *Header {
h.MaxItems = &size
return h
}
// WithMinItems sets the min items
func (h *Header) WithMinItems(size int64) *Header {
h.MinItems = &size
return h
}
// UniqueValues dictates that this array can only have unique items
func (h *Header) UniqueValues() *Header {
h.UniqueItems = true
return h
}
// AllowDuplicates this array can have duplicates
func (h *Header) AllowDuplicates() *Header {
h.UniqueItems = false
return h
}
// MarshalJSON marshal this to JSON
func (h Header) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(h.CommonValidations)
if err != nil {
return nil, err
}
b2, err := json.Marshal(h.SimpleSchema)
if err != nil {
return nil, err
}
b3, err := json.Marshal(h.HeaderProps)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2, b3), nil
}
// UnmarshalJSON unmarshals this header from JSON
func (h *Header) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &h.CommonValidations); err != nil {
return err
}
if err := json.Unmarshal(data, &h.SimpleSchema); err != nil {
return err
}
if err := json.Unmarshal(data, &h.VendorExtensible); err != nil {
return err
}
return json.Unmarshal(data, &h.HeaderProps)
}
// JSONLookup look up a value by the json property name
func (h Header) JSONLookup(token string) (interface{}, error) {
if ex, ok := h.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(h.CommonValidations, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(h.SimpleSchema, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(h.HeaderProps, token)
return r, err
}

168
src/runtime/vendor/github.com/go-openapi/spec/info.go generated vendored Normal file
View File

@@ -0,0 +1,168 @@
// 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 spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// Extensions vendor specific extensions
type Extensions map[string]interface{}
// Add adds a value to these extensions
func (e Extensions) Add(key string, value interface{}) {
realKey := strings.ToLower(key)
e[realKey] = value
}
// GetString gets a string value from the extensions
func (e Extensions) GetString(key string) (string, bool) {
if v, ok := e[strings.ToLower(key)]; ok {
str, ok := v.(string)
return str, ok
}
return "", false
}
// GetBool gets a string value from the extensions
func (e Extensions) GetBool(key string) (bool, bool) {
if v, ok := e[strings.ToLower(key)]; ok {
str, ok := v.(bool)
return str, ok
}
return false, false
}
// GetStringSlice gets a string value from the extensions
func (e Extensions) GetStringSlice(key string) ([]string, bool) {
if v, ok := e[strings.ToLower(key)]; ok {
arr, isSlice := v.([]interface{})
if !isSlice {
return nil, false
}
var strs []string
for _, iface := range arr {
str, isString := iface.(string)
if !isString {
return nil, false
}
strs = append(strs, str)
}
return strs, ok
}
return nil, false
}
// VendorExtensible composition block.
type VendorExtensible struct {
Extensions Extensions
}
// AddExtension adds an extension to this extensible object
func (v *VendorExtensible) AddExtension(key string, value interface{}) {
if value == nil {
return
}
if v.Extensions == nil {
v.Extensions = make(map[string]interface{})
}
v.Extensions.Add(key, value)
}
// MarshalJSON marshals the extensions to json
func (v VendorExtensible) MarshalJSON() ([]byte, error) {
toser := make(map[string]interface{})
for k, v := range v.Extensions {
lk := strings.ToLower(k)
if strings.HasPrefix(lk, "x-") {
toser[k] = v
}
}
return json.Marshal(toser)
}
// UnmarshalJSON for this extensible object
func (v *VendorExtensible) UnmarshalJSON(data []byte) error {
var d map[string]interface{}
if err := json.Unmarshal(data, &d); err != nil {
return err
}
for k, vv := range d {
lk := strings.ToLower(k)
if strings.HasPrefix(lk, "x-") {
if v.Extensions == nil {
v.Extensions = map[string]interface{}{}
}
v.Extensions[k] = vv
}
}
return nil
}
// InfoProps the properties for an info definition
type InfoProps struct {
Description string `json:"description,omitempty"`
Title string `json:"title,omitempty"`
TermsOfService string `json:"termsOfService,omitempty"`
Contact *ContactInfo `json:"contact,omitempty"`
License *License `json:"license,omitempty"`
Version string `json:"version,omitempty"`
}
// Info object provides metadata about the API.
// The metadata can be used by the clients if needed, and can be presented in the Swagger-UI for convenience.
//
// For more information: http://goo.gl/8us55a#infoObject
type Info struct {
VendorExtensible
InfoProps
}
// JSONLookup look up a value by the json property name
func (i Info) JSONLookup(token string) (interface{}, error) {
if ex, ok := i.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(i.InfoProps, token)
return r, err
}
// MarshalJSON marshal this to JSON
func (i Info) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(i.InfoProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(i.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON marshal this from JSON
func (i *Info) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &i.InfoProps); err != nil {
return err
}
if err := json.Unmarshal(data, &i.VendorExtensible); err != nil {
return err
}
return nil
}

233
src/runtime/vendor/github.com/go-openapi/spec/items.go generated vendored Normal file
View File

@@ -0,0 +1,233 @@
// 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 spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// SimpleSchema describe swagger simple schemas for parameters and headers
type SimpleSchema struct {
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Items *Items `json:"items,omitempty"`
CollectionFormat string `json:"collectionFormat,omitempty"`
Default interface{} `json:"default,omitempty"`
Example interface{} `json:"example,omitempty"`
}
// TypeName return the type (or format) of a simple schema
func (s *SimpleSchema) TypeName() string {
if s.Format != "" {
return s.Format
}
return s.Type
}
// ItemsTypeName yields the type of items in a simple schema array
func (s *SimpleSchema) ItemsTypeName() string {
if s.Items == nil {
return ""
}
return s.Items.TypeName()
}
// CommonValidations describe common JSON-schema validations
type CommonValidations struct {
Maximum *float64 `json:"maximum,omitempty"`
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
Minimum *float64 `json:"minimum,omitempty"`
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
MaxLength *int64 `json:"maxLength,omitempty"`
MinLength *int64 `json:"minLength,omitempty"`
Pattern string `json:"pattern,omitempty"`
MaxItems *int64 `json:"maxItems,omitempty"`
MinItems *int64 `json:"minItems,omitempty"`
UniqueItems bool `json:"uniqueItems,omitempty"`
MultipleOf *float64 `json:"multipleOf,omitempty"`
Enum []interface{} `json:"enum,omitempty"`
}
// Items a limited subset of JSON-Schema's items object.
// It is used by parameter definitions that are not located in "body".
//
// For more information: http://goo.gl/8us55a#items-object
type Items struct {
Refable
CommonValidations
SimpleSchema
VendorExtensible
}
// NewItems creates a new instance of items
func NewItems() *Items {
return &Items{}
}
// Typed a fluent builder method for the type of item
func (i *Items) Typed(tpe, format string) *Items {
i.Type = tpe
i.Format = format
return i
}
// CollectionOf a fluent builder method for an array item
func (i *Items) CollectionOf(items *Items, format string) *Items {
i.Type = "array"
i.Items = items
i.CollectionFormat = format
return i
}
// WithDefault sets the default value on this item
func (i *Items) WithDefault(defaultValue interface{}) *Items {
i.Default = defaultValue
return i
}
// WithMaxLength sets a max length value
func (i *Items) WithMaxLength(max int64) *Items {
i.MaxLength = &max
return i
}
// WithMinLength sets a min length value
func (i *Items) WithMinLength(min int64) *Items {
i.MinLength = &min
return i
}
// WithPattern sets a pattern value
func (i *Items) WithPattern(pattern string) *Items {
i.Pattern = pattern
return i
}
// WithMultipleOf sets a multiple of value
func (i *Items) WithMultipleOf(number float64) *Items {
i.MultipleOf = &number
return i
}
// WithMaximum sets a maximum number value
func (i *Items) WithMaximum(max float64, exclusive bool) *Items {
i.Maximum = &max
i.ExclusiveMaximum = exclusive
return i
}
// WithMinimum sets a minimum number value
func (i *Items) WithMinimum(min float64, exclusive bool) *Items {
i.Minimum = &min
i.ExclusiveMinimum = exclusive
return i
}
// WithEnum sets a the enum values (replace)
func (i *Items) WithEnum(values ...interface{}) *Items {
i.Enum = append([]interface{}{}, values...)
return i
}
// WithMaxItems sets the max items
func (i *Items) WithMaxItems(size int64) *Items {
i.MaxItems = &size
return i
}
// WithMinItems sets the min items
func (i *Items) WithMinItems(size int64) *Items {
i.MinItems = &size
return i
}
// UniqueValues dictates that this array can only have unique items
func (i *Items) UniqueValues() *Items {
i.UniqueItems = true
return i
}
// AllowDuplicates this array can have duplicates
func (i *Items) AllowDuplicates() *Items {
i.UniqueItems = false
return i
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (i *Items) UnmarshalJSON(data []byte) error {
var validations CommonValidations
if err := json.Unmarshal(data, &validations); err != nil {
return err
}
var ref Refable
if err := json.Unmarshal(data, &ref); err != nil {
return err
}
var simpleSchema SimpleSchema
if err := json.Unmarshal(data, &simpleSchema); err != nil {
return err
}
var vendorExtensible VendorExtensible
if err := json.Unmarshal(data, &vendorExtensible); err != nil {
return err
}
i.Refable = ref
i.CommonValidations = validations
i.SimpleSchema = simpleSchema
i.VendorExtensible = vendorExtensible
return nil
}
// MarshalJSON converts this items object to JSON
func (i Items) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(i.CommonValidations)
if err != nil {
return nil, err
}
b2, err := json.Marshal(i.SimpleSchema)
if err != nil {
return nil, err
}
b3, err := json.Marshal(i.Refable)
if err != nil {
return nil, err
}
b4, err := json.Marshal(i.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b4, b3, b1, b2), nil
}
// JSONLookup look up a value by the json property name
func (i Items) JSONLookup(token string) (interface{}, error) {
if token == "$ref" {
return &i.Ref, nil
}
r, _, err := jsonpointer.GetForToken(i.CommonValidations, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(i.SimpleSchema, token)
return r, err
}

View File

@@ -0,0 +1,23 @@
// 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 spec
// License information for the exposed API.
//
// For more information: http://goo.gl/8us55a#licenseObject
type License struct {
Name string `json:"name,omitempty"`
URL string `json:"url,omitempty"`
}

View File

@@ -0,0 +1,390 @@
// 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 spec
import (
"bytes"
"encoding/gob"
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
func init() {
//gob.Register(map[string][]interface{}{})
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
}
// OperationProps describes an operation
type OperationProps struct {
Description string `json:"description,omitempty"`
Consumes []string `json:"consumes,omitempty"`
Produces []string `json:"produces,omitempty"`
Schemes []string `json:"schemes,omitempty"` // the scheme, when present must be from [http, https, ws, wss]
Tags []string `json:"tags,omitempty"`
Summary string `json:"summary,omitempty"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
ID string `json:"operationId,omitempty"`
Deprecated bool `json:"deprecated,omitempty"`
Security []map[string][]string `json:"security,omitempty"` //Special case, see MarshalJSON function
Parameters []Parameter `json:"parameters,omitempty"`
Responses *Responses `json:"responses,omitempty"`
}
// MarshalJSON takes care of serializing operation properties to JSON
//
// We use a custom marhaller here to handle a special cases related to
// the Security field. We need to preserve zero length slice
// while omitting the field when the value is nil/unset.
func (op OperationProps) MarshalJSON() ([]byte, error) {
type Alias OperationProps
if op.Security == nil {
return json.Marshal(&struct {
Security []map[string][]string `json:"security,omitempty"`
*Alias
}{
Security: op.Security,
Alias: (*Alias)(&op),
})
}
return json.Marshal(&struct {
Security []map[string][]string `json:"security"`
*Alias
}{
Security: op.Security,
Alias: (*Alias)(&op),
})
}
// Operation describes a single API operation on a path.
//
// For more information: http://goo.gl/8us55a#operationObject
type Operation struct {
VendorExtensible
OperationProps
}
// SuccessResponse gets a success response model
func (o *Operation) SuccessResponse() (*Response, int, bool) {
if o.Responses == nil {
return nil, 0, false
}
for k, v := range o.Responses.StatusCodeResponses {
if k/100 == 2 {
return &v, k, true
}
}
return o.Responses.Default, 0, false
}
// JSONLookup look up a value by the json property name
func (o Operation) JSONLookup(token string) (interface{}, error) {
if ex, ok := o.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(o.OperationProps, token)
return r, err
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (o *Operation) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &o.OperationProps); err != nil {
return err
}
if err := json.Unmarshal(data, &o.VendorExtensible); err != nil {
return err
}
return nil
}
// MarshalJSON converts this items object to JSON
func (o Operation) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(o.OperationProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(o.VendorExtensible)
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b1, b2)
return concated, nil
}
// NewOperation creates a new operation instance.
// It expects an ID as parameter but not passing an ID is also valid.
func NewOperation(id string) *Operation {
op := new(Operation)
op.ID = id
return op
}
// WithID sets the ID property on this operation, allows for chaining.
func (o *Operation) WithID(id string) *Operation {
o.ID = id
return o
}
// WithDescription sets the description on this operation, allows for chaining
func (o *Operation) WithDescription(description string) *Operation {
o.Description = description
return o
}
// WithSummary sets the summary on this operation, allows for chaining
func (o *Operation) WithSummary(summary string) *Operation {
o.Summary = summary
return o
}
// WithExternalDocs sets/removes the external docs for/from this operation.
// When you pass empty strings as params the external documents will be removed.
// When you pass non-empty string as one value then those values will be used on the external docs object.
// So when you pass a non-empty description, you should also pass the url and vice versa.
func (o *Operation) WithExternalDocs(description, url string) *Operation {
if description == "" && url == "" {
o.ExternalDocs = nil
return o
}
if o.ExternalDocs == nil {
o.ExternalDocs = &ExternalDocumentation{}
}
o.ExternalDocs.Description = description
o.ExternalDocs.URL = url
return o
}
// Deprecate marks the operation as deprecated
func (o *Operation) Deprecate() *Operation {
o.Deprecated = true
return o
}
// Undeprecate marks the operation as not deprected
func (o *Operation) Undeprecate() *Operation {
o.Deprecated = false
return o
}
// WithConsumes adds media types for incoming body values
func (o *Operation) WithConsumes(mediaTypes ...string) *Operation {
o.Consumes = append(o.Consumes, mediaTypes...)
return o
}
// WithProduces adds media types for outgoing body values
func (o *Operation) WithProduces(mediaTypes ...string) *Operation {
o.Produces = append(o.Produces, mediaTypes...)
return o
}
// WithTags adds tags for this operation
func (o *Operation) WithTags(tags ...string) *Operation {
o.Tags = append(o.Tags, tags...)
return o
}
// AddParam adds a parameter to this operation, when a parameter for that location
// and with that name already exists it will be replaced
func (o *Operation) AddParam(param *Parameter) *Operation {
if param == nil {
return o
}
for i, p := range o.Parameters {
if p.Name == param.Name && p.In == param.In {
params := append(o.Parameters[:i], *param)
params = append(params, o.Parameters[i+1:]...)
o.Parameters = params
return o
}
}
o.Parameters = append(o.Parameters, *param)
return o
}
// RemoveParam removes a parameter from the operation
func (o *Operation) RemoveParam(name, in string) *Operation {
for i, p := range o.Parameters {
if p.Name == name && p.In == name {
o.Parameters = append(o.Parameters[:i], o.Parameters[i+1:]...)
return o
}
}
return o
}
// SecuredWith adds a security scope to this operation.
func (o *Operation) SecuredWith(name string, scopes ...string) *Operation {
o.Security = append(o.Security, map[string][]string{name: scopes})
return o
}
// WithDefaultResponse adds a default response to the operation.
// Passing a nil value will remove the response
func (o *Operation) WithDefaultResponse(response *Response) *Operation {
return o.RespondsWith(0, response)
}
// RespondsWith adds a status code response to the operation.
// When the code is 0 the value of the response will be used as default response value.
// When the value of the response is nil it will be removed from the operation
func (o *Operation) RespondsWith(code int, response *Response) *Operation {
if o.Responses == nil {
o.Responses = new(Responses)
}
if code == 0 {
o.Responses.Default = response
return o
}
if response == nil {
delete(o.Responses.StatusCodeResponses, code)
return o
}
if o.Responses.StatusCodeResponses == nil {
o.Responses.StatusCodeResponses = make(map[int]Response)
}
o.Responses.StatusCodeResponses[code] = *response
return o
}
type opsAlias OperationProps
type gobAlias struct {
Security []map[string]struct {
List []string
Pad bool
}
Alias *opsAlias
SecurityIsEmpty bool
}
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
func (o Operation) GobEncode() ([]byte, error) {
raw := struct {
Ext VendorExtensible
Props OperationProps
}{
Ext: o.VendorExtensible,
Props: o.OperationProps,
}
var b bytes.Buffer
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
func (o *Operation) GobDecode(b []byte) error {
var raw struct {
Ext VendorExtensible
Props OperationProps
}
buf := bytes.NewBuffer(b)
err := gob.NewDecoder(buf).Decode(&raw)
if err != nil {
return err
}
o.VendorExtensible = raw.Ext
o.OperationProps = raw.Props
return nil
}
// GobEncode provides a safe gob encoder for Operation, including empty security requirements
func (op OperationProps) GobEncode() ([]byte, error) {
raw := gobAlias{
Alias: (*opsAlias)(&op),
}
var b bytes.Buffer
if op.Security == nil {
// nil security requirement
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
if len(op.Security) == 0 {
// empty, but non-nil security requirement
raw.SecurityIsEmpty = true
raw.Alias.Security = nil
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
raw.Security = make([]map[string]struct {
List []string
Pad bool
}, 0, len(op.Security))
for _, req := range op.Security {
v := make(map[string]struct {
List []string
Pad bool
}, len(req))
for k, val := range req {
v[k] = struct {
List []string
Pad bool
}{
List: val,
}
}
raw.Security = append(raw.Security, v)
}
err := gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
// GobDecode provides a safe gob decoder for Operation, including empty security requirements
func (op *OperationProps) GobDecode(b []byte) error {
var raw gobAlias
buf := bytes.NewBuffer(b)
err := gob.NewDecoder(buf).Decode(&raw)
if err != nil {
return err
}
if raw.Alias == nil {
return nil
}
switch {
case raw.SecurityIsEmpty:
// empty, but non-nil security requirement
raw.Alias.Security = []map[string][]string{}
case len(raw.Alias.Security) == 0:
// nil security requirement
raw.Alias.Security = nil
default:
raw.Alias.Security = make([]map[string][]string, 0, len(raw.Security))
for _, req := range raw.Security {
v := make(map[string][]string, len(req))
for k, val := range req {
v[k] = make([]string, 0, len(val.List))
v[k] = append(v[k], val.List...)
}
raw.Alias.Security = append(raw.Alias.Security, v)
}
}
*op = *(*OperationProps)(raw.Alias)
return nil
}

View File

@@ -0,0 +1,302 @@
// 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 spec
import (
"encoding/json"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// QueryParam creates a query parameter
func QueryParam(name string) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name, In: "query"}}
}
// HeaderParam creates a header parameter, this is always required by default
func HeaderParam(name string) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name, In: "header", Required: true}}
}
// PathParam creates a path parameter, this is always required
func PathParam(name string) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name, In: "path", Required: true}}
}
// BodyParam creates a body parameter
func BodyParam(name string, schema *Schema) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name, In: "body", Schema: schema}, SimpleSchema: SimpleSchema{Type: "object"}}
}
// FormDataParam creates a body parameter
func FormDataParam(name string) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}}
}
// FileParam creates a body parameter
func FileParam(name string) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name, In: "formData"}, SimpleSchema: SimpleSchema{Type: "file"}}
}
// SimpleArrayParam creates a param for a simple array (string, int, date etc)
func SimpleArrayParam(name, tpe, fmt string) *Parameter {
return &Parameter{ParamProps: ParamProps{Name: name}, SimpleSchema: SimpleSchema{Type: "array", CollectionFormat: "csv", Items: &Items{SimpleSchema: SimpleSchema{Type: "string", Format: fmt}}}}
}
// ParamRef creates a parameter that's a json reference
func ParamRef(uri string) *Parameter {
p := new(Parameter)
p.Ref = MustCreateRef(uri)
return p
}
// ParamProps describes the specific attributes of an operation parameter
type ParamProps struct {
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
In string `json:"in,omitempty"`
Required bool `json:"required,omitempty"`
Schema *Schema `json:"schema,omitempty"` // when in == "body"
AllowEmptyValue bool `json:"allowEmptyValue,omitempty"` // when in == "query" || "formData"
}
// Parameter a unique parameter is defined by a combination of a [name](#parameterName) and [location](#parameterIn).
//
// There are five possible parameter types.
// * Path - Used together with [Path Templating](#pathTemplating), where the parameter value is actually part of the operation's URL. This does not include the host or base path of the API. For example, in `/items/{itemId}`, the path parameter is `itemId`.
// * Query - Parameters that are appended to the URL. For example, in `/items?id=###`, the query parameter is `id`.
// * Header - Custom headers that are expected as part of the request.
// * Body - The payload that's appended to the HTTP request. Since there can only be one payload, there can only be *one* body parameter. The name of the body parameter has no effect on the parameter itself and is used for documentation purposes only. Since Form parameters are also in the payload, body and form parameters cannot exist together for the same operation.
// * Form - Used to describe the payload of an HTTP request when either `application/x-www-form-urlencoded` or `multipart/form-data` are used as the content type of the request (in Swagger's definition, the [`consumes`](#operationConsumes) property of an operation). This is the only parameter type that can be used to send files, thus supporting the `file` type. Since form parameters are sent in the payload, they cannot be declared together with a body parameter for the same operation. Form parameters have a different format based on the content-type used (for further details, consult http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4):
// * `application/x-www-form-urlencoded` - Similar to the format of Query parameters but as a payload. For example, `foo=1&bar=swagger` - both `foo` and `bar` are form parameters. This is normally used for simple parameters that are being transferred.
// * `multipart/form-data` - each parameter takes a section in the payload with an internal header. For example, for the header `Content-Disposition: form-data; name="submit-name"` the name of the parameter is `submit-name`. This type of form parameters is more commonly used for file transfers.
//
// For more information: http://goo.gl/8us55a#parameterObject
type Parameter struct {
Refable
CommonValidations
SimpleSchema
VendorExtensible
ParamProps
}
// JSONLookup look up a value by the json property name
func (p Parameter) JSONLookup(token string) (interface{}, error) {
if ex, ok := p.Extensions[token]; ok {
return &ex, nil
}
if token == "$ref" {
return &p.Ref, nil
}
r, _, err := jsonpointer.GetForToken(p.CommonValidations, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(p.SimpleSchema, token)
if err != nil && !strings.HasPrefix(err.Error(), "object has no field") {
return nil, err
}
if r != nil {
return r, nil
}
r, _, err = jsonpointer.GetForToken(p.ParamProps, token)
return r, err
}
// WithDescription a fluent builder method for the description of the parameter
func (p *Parameter) WithDescription(description string) *Parameter {
p.Description = description
return p
}
// Named a fluent builder method to override the name of the parameter
func (p *Parameter) Named(name string) *Parameter {
p.Name = name
return p
}
// WithLocation a fluent builder method to override the location of the parameter
func (p *Parameter) WithLocation(in string) *Parameter {
p.In = in
return p
}
// Typed a fluent builder method for the type of the parameter value
func (p *Parameter) Typed(tpe, format string) *Parameter {
p.Type = tpe
p.Format = format
return p
}
// CollectionOf a fluent builder method for an array parameter
func (p *Parameter) CollectionOf(items *Items, format string) *Parameter {
p.Type = "array"
p.Items = items
p.CollectionFormat = format
return p
}
// WithDefault sets the default value on this parameter
func (p *Parameter) WithDefault(defaultValue interface{}) *Parameter {
p.AsOptional() // with default implies optional
p.Default = defaultValue
return p
}
// AllowsEmptyValues flags this parameter as being ok with empty values
func (p *Parameter) AllowsEmptyValues() *Parameter {
p.AllowEmptyValue = true
return p
}
// NoEmptyValues flags this parameter as not liking empty values
func (p *Parameter) NoEmptyValues() *Parameter {
p.AllowEmptyValue = false
return p
}
// AsOptional flags this parameter as optional
func (p *Parameter) AsOptional() *Parameter {
p.Required = false
return p
}
// AsRequired flags this parameter as required
func (p *Parameter) AsRequired() *Parameter {
if p.Default != nil { // with a default required makes no sense
return p
}
p.Required = true
return p
}
// WithMaxLength sets a max length value
func (p *Parameter) WithMaxLength(max int64) *Parameter {
p.MaxLength = &max
return p
}
// WithMinLength sets a min length value
func (p *Parameter) WithMinLength(min int64) *Parameter {
p.MinLength = &min
return p
}
// WithPattern sets a pattern value
func (p *Parameter) WithPattern(pattern string) *Parameter {
p.Pattern = pattern
return p
}
// WithMultipleOf sets a multiple of value
func (p *Parameter) WithMultipleOf(number float64) *Parameter {
p.MultipleOf = &number
return p
}
// WithMaximum sets a maximum number value
func (p *Parameter) WithMaximum(max float64, exclusive bool) *Parameter {
p.Maximum = &max
p.ExclusiveMaximum = exclusive
return p
}
// WithMinimum sets a minimum number value
func (p *Parameter) WithMinimum(min float64, exclusive bool) *Parameter {
p.Minimum = &min
p.ExclusiveMinimum = exclusive
return p
}
// WithEnum sets a the enum values (replace)
func (p *Parameter) WithEnum(values ...interface{}) *Parameter {
p.Enum = append([]interface{}{}, values...)
return p
}
// WithMaxItems sets the max items
func (p *Parameter) WithMaxItems(size int64) *Parameter {
p.MaxItems = &size
return p
}
// WithMinItems sets the min items
func (p *Parameter) WithMinItems(size int64) *Parameter {
p.MinItems = &size
return p
}
// UniqueValues dictates that this array can only have unique items
func (p *Parameter) UniqueValues() *Parameter {
p.UniqueItems = true
return p
}
// AllowDuplicates this array can have duplicates
func (p *Parameter) AllowDuplicates() *Parameter {
p.UniqueItems = false
return p
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (p *Parameter) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &p.CommonValidations); err != nil {
return err
}
if err := json.Unmarshal(data, &p.Refable); err != nil {
return err
}
if err := json.Unmarshal(data, &p.SimpleSchema); err != nil {
return err
}
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
return err
}
if err := json.Unmarshal(data, &p.ParamProps); err != nil {
return err
}
return nil
}
// MarshalJSON converts this items object to JSON
func (p Parameter) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(p.CommonValidations)
if err != nil {
return nil, err
}
b2, err := json.Marshal(p.SimpleSchema)
if err != nil {
return nil, err
}
b3, err := json.Marshal(p.Refable)
if err != nil {
return nil, err
}
b4, err := json.Marshal(p.VendorExtensible)
if err != nil {
return nil, err
}
b5, err := json.Marshal(p.ParamProps)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b3, b1, b2, b4, b5), nil
}

View 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 spec
import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// PathItemProps the path item specific properties
type PathItemProps struct {
Get *Operation `json:"get,omitempty"`
Put *Operation `json:"put,omitempty"`
Post *Operation `json:"post,omitempty"`
Delete *Operation `json:"delete,omitempty"`
Options *Operation `json:"options,omitempty"`
Head *Operation `json:"head,omitempty"`
Patch *Operation `json:"patch,omitempty"`
Parameters []Parameter `json:"parameters,omitempty"`
}
// PathItem describes the operations available on a single path.
// A Path Item may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
// The path itself is still exposed to the documentation viewer but they will
// not know which operations and parameters are available.
//
// For more information: http://goo.gl/8us55a#pathItemObject
type PathItem struct {
Refable
VendorExtensible
PathItemProps
}
// JSONLookup look up a value by the json property name
func (p PathItem) JSONLookup(token string) (interface{}, error) {
if ex, ok := p.Extensions[token]; ok {
return &ex, nil
}
if token == "$ref" {
return &p.Ref, nil
}
r, _, err := jsonpointer.GetForToken(p.PathItemProps, token)
return r, err
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (p *PathItem) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &p.Refable); err != nil {
return err
}
if err := json.Unmarshal(data, &p.VendorExtensible); err != nil {
return err
}
if err := json.Unmarshal(data, &p.PathItemProps); err != nil {
return err
}
return nil
}
// MarshalJSON converts this items object to JSON
func (p PathItem) MarshalJSON() ([]byte, error) {
b3, err := json.Marshal(p.Refable)
if err != nil {
return nil, err
}
b4, err := json.Marshal(p.VendorExtensible)
if err != nil {
return nil, err
}
b5, err := json.Marshal(p.PathItemProps)
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b3, b4, b5)
return concated, nil
}

97
src/runtime/vendor/github.com/go-openapi/spec/paths.go generated vendored Normal file
View File

@@ -0,0 +1,97 @@
// 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 spec
import (
"encoding/json"
"fmt"
"strings"
"github.com/go-openapi/swag"
)
// Paths holds the relative paths to the individual endpoints.
// The path is appended to the [`basePath`](http://goo.gl/8us55a#swaggerBasePath) in order
// to construct the full URL.
// The Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
//
// For more information: http://goo.gl/8us55a#pathsObject
type Paths struct {
VendorExtensible
Paths map[string]PathItem `json:"-"` // custom serializer to flatten this, each entry must start with "/"
}
// JSONLookup look up a value by the json property name
func (p Paths) JSONLookup(token string) (interface{}, error) {
if pi, ok := p.Paths[token]; ok {
return &pi, nil
}
if ex, ok := p.Extensions[token]; ok {
return &ex, nil
}
return nil, fmt.Errorf("object has no field %q", token)
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (p *Paths) UnmarshalJSON(data []byte) error {
var res map[string]json.RawMessage
if err := json.Unmarshal(data, &res); err != nil {
return err
}
for k, v := range res {
if strings.HasPrefix(strings.ToLower(k), "x-") {
if p.Extensions == nil {
p.Extensions = make(map[string]interface{})
}
var d interface{}
if err := json.Unmarshal(v, &d); err != nil {
return err
}
p.Extensions[k] = d
}
if strings.HasPrefix(k, "/") {
if p.Paths == nil {
p.Paths = make(map[string]PathItem)
}
var pi PathItem
if err := json.Unmarshal(v, &pi); err != nil {
return err
}
p.Paths[k] = pi
}
}
return nil
}
// MarshalJSON converts this items object to JSON
func (p Paths) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(p.VendorExtensible)
if err != nil {
return nil, err
}
pths := make(map[string]PathItem)
for k, v := range p.Paths {
if strings.HasPrefix(k, "/") {
pths[k] = v
}
}
b2, err := json.Marshal(pths)
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b1, b2)
return concated, nil
}

191
src/runtime/vendor/github.com/go-openapi/spec/ref.go generated vendored Normal file
View File

@@ -0,0 +1,191 @@
// 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 spec
import (
"bytes"
"encoding/gob"
"encoding/json"
"net/http"
"os"
"path/filepath"
"github.com/go-openapi/jsonreference"
)
// Refable is a struct for things that accept a $ref property
type Refable struct {
Ref Ref
}
// MarshalJSON marshals the ref to json
func (r Refable) MarshalJSON() ([]byte, error) {
return r.Ref.MarshalJSON()
}
// UnmarshalJSON unmarshalss the ref from json
func (r *Refable) UnmarshalJSON(d []byte) error {
return json.Unmarshal(d, &r.Ref)
}
// Ref represents a json reference that is potentially resolved
type Ref struct {
jsonreference.Ref
}
// RemoteURI gets the remote uri part of the ref
func (r *Ref) RemoteURI() string {
if r.String() == "" {
return r.String()
}
u := *r.GetURL()
u.Fragment = ""
return u.String()
}
// IsValidURI returns true when the url the ref points to can be found
func (r *Ref) IsValidURI(basepaths ...string) bool {
if r.String() == "" {
return true
}
v := r.RemoteURI()
if v == "" {
return true
}
if r.HasFullURL {
rr, err := http.Get(v)
if err != nil {
return false
}
return rr.StatusCode/100 == 2
}
if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) {
return false
}
// check for local file
pth := v
if r.HasURLPathOnly {
base := "."
if len(basepaths) > 0 {
base = filepath.Dir(filepath.Join(basepaths...))
}
p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth)))
if e != nil {
return false
}
pth = p
}
fi, err := os.Stat(filepath.ToSlash(pth))
if err != nil {
return false
}
return !fi.IsDir()
}
// Inherits creates a new reference from a parent and a child
// If the child cannot inherit from the parent, an error is returned
func (r *Ref) Inherits(child Ref) (*Ref, error) {
ref, err := r.Ref.Inherits(child.Ref)
if err != nil {
return nil, err
}
return &Ref{Ref: *ref}, nil
}
// NewRef creates a new instance of a ref object
// returns an error when the reference uri is an invalid uri
func NewRef(refURI string) (Ref, error) {
ref, err := jsonreference.New(refURI)
if err != nil {
return Ref{}, err
}
return Ref{Ref: ref}, nil
}
// MustCreateRef creates a ref object but panics when refURI is invalid.
// Use the NewRef method for a version that returns an error.
func MustCreateRef(refURI string) Ref {
return Ref{Ref: jsonreference.MustCreateRef(refURI)}
}
// MarshalJSON marshals this ref into a JSON object
func (r Ref) MarshalJSON() ([]byte, error) {
str := r.String()
if str == "" {
if r.IsRoot() {
return []byte(`{"$ref":""}`), nil
}
return []byte("{}"), nil
}
v := map[string]interface{}{"$ref": str}
return json.Marshal(v)
}
// UnmarshalJSON unmarshals this ref from a JSON object
func (r *Ref) UnmarshalJSON(d []byte) error {
var v map[string]interface{}
if err := json.Unmarshal(d, &v); err != nil {
return err
}
return r.fromMap(v)
}
// GobEncode provides a safe gob encoder for Ref
func (r Ref) GobEncode() ([]byte, error) {
var b bytes.Buffer
raw, err := r.MarshalJSON()
if err != nil {
return nil, err
}
err = gob.NewEncoder(&b).Encode(raw)
return b.Bytes(), err
}
// GobDecode provides a safe gob decoder for Ref
func (r *Ref) GobDecode(b []byte) error {
var raw []byte
buf := bytes.NewBuffer(b)
err := gob.NewDecoder(buf).Decode(&raw)
if err != nil {
return err
}
return json.Unmarshal(raw, r)
}
func (r *Ref) fromMap(v map[string]interface{}) error {
if v == nil {
return nil
}
if vv, ok := v["$ref"]; ok {
if str, ok := vv.(string); ok {
ref, err := jsonreference.New(str)
if err != nil {
return err
}
*r = Ref{Ref: ref}
}
}
return nil
}

View File

@@ -0,0 +1,134 @@
// 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 spec
import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// ResponseProps properties specific to a response
type ResponseProps struct {
Description string `json:"description,omitempty"`
Schema *Schema `json:"schema,omitempty"`
Headers map[string]Header `json:"headers,omitempty"`
Examples map[string]interface{} `json:"examples,omitempty"`
}
// Response describes a single response from an API Operation.
//
// For more information: http://goo.gl/8us55a#responseObject
type Response struct {
Refable
ResponseProps
VendorExtensible
}
// JSONLookup look up a value by the json property name
func (r Response) JSONLookup(token string) (interface{}, error) {
if ex, ok := r.Extensions[token]; ok {
return &ex, nil
}
if token == "$ref" {
return &r.Ref, nil
}
ptr, _, err := jsonpointer.GetForToken(r.ResponseProps, token)
return ptr, err
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (r *Response) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &r.ResponseProps); err != nil {
return err
}
if err := json.Unmarshal(data, &r.Refable); err != nil {
return err
}
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
return err
}
return nil
}
// MarshalJSON converts this items object to JSON
func (r Response) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(r.ResponseProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(r.Refable)
if err != nil {
return nil, err
}
b3, err := json.Marshal(r.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2, b3), nil
}
// NewResponse creates a new response instance
func NewResponse() *Response {
return new(Response)
}
// ResponseRef creates a response as a json reference
func ResponseRef(url string) *Response {
resp := NewResponse()
resp.Ref = MustCreateRef(url)
return resp
}
// WithDescription sets the description on this response, allows for chaining
func (r *Response) WithDescription(description string) *Response {
r.Description = description
return r
}
// WithSchema sets the schema on this response, allows for chaining.
// Passing a nil argument removes the schema from this response
func (r *Response) WithSchema(schema *Schema) *Response {
r.Schema = schema
return r
}
// AddHeader adds a header to this response
func (r *Response) AddHeader(name string, header *Header) *Response {
if header == nil {
return r.RemoveHeader(name)
}
if r.Headers == nil {
r.Headers = make(map[string]Header)
}
r.Headers[name] = *header
return r
}
// RemoveHeader removes a header from this response
func (r *Response) RemoveHeader(name string) *Response {
delete(r.Headers, name)
return r
}
// AddExample adds an example to this response
func (r *Response) AddExample(mediaType string, example interface{}) *Response {
if r.Examples == nil {
r.Examples = make(map[string]interface{})
}
r.Examples[mediaType] = example
return r
}

View File

@@ -0,0 +1,127 @@
// 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 spec
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"github.com/go-openapi/swag"
)
// Responses is a container for the expected responses of an operation.
// The container maps a HTTP response code to the expected response.
// It is not expected from the documentation to necessarily cover all possible HTTP response codes,
// since they may not be known in advance. However, it is expected from the documentation to cover
// a successful operation response and any known errors.
//
// The `default` can be used a default response object for all HTTP codes that are not covered
// individually by the specification.
//
// The `Responses Object` MUST contain at least one response code, and it SHOULD be the response
// for a successful operation call.
//
// For more information: http://goo.gl/8us55a#responsesObject
type Responses struct {
VendorExtensible
ResponsesProps
}
// JSONLookup implements an interface to customize json pointer lookup
func (r Responses) JSONLookup(token string) (interface{}, error) {
if token == "default" {
return r.Default, nil
}
if ex, ok := r.Extensions[token]; ok {
return &ex, nil
}
if i, err := strconv.Atoi(token); err == nil {
if scr, ok := r.StatusCodeResponses[i]; ok {
return scr, nil
}
}
return nil, fmt.Errorf("object has no field %q", token)
}
// UnmarshalJSON hydrates this items instance with the data from JSON
func (r *Responses) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &r.ResponsesProps); err != nil {
return err
}
if err := json.Unmarshal(data, &r.VendorExtensible); err != nil {
return err
}
if reflect.DeepEqual(ResponsesProps{}, r.ResponsesProps) {
r.ResponsesProps = ResponsesProps{}
}
return nil
}
// MarshalJSON converts this items object to JSON
func (r Responses) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(r.ResponsesProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(r.VendorExtensible)
if err != nil {
return nil, err
}
concated := swag.ConcatJSON(b1, b2)
return concated, nil
}
// ResponsesProps describes all responses for an operation.
// It tells what is the default response and maps all responses with a
// HTTP status code.
type ResponsesProps struct {
Default *Response
StatusCodeResponses map[int]Response
}
// MarshalJSON marshals responses as JSON
func (r ResponsesProps) MarshalJSON() ([]byte, error) {
toser := map[string]Response{}
if r.Default != nil {
toser["default"] = *r.Default
}
for k, v := range r.StatusCodeResponses {
toser[strconv.Itoa(k)] = v
}
return json.Marshal(toser)
}
// UnmarshalJSON unmarshals responses from JSON
func (r *ResponsesProps) UnmarshalJSON(data []byte) error {
var res map[string]Response
if err := json.Unmarshal(data, &res); err != nil {
return nil
}
if v, ok := res["default"]; ok {
r.Default = &v
delete(res, "default")
}
for k, v := range res {
if nk, err := strconv.Atoi(k); err == nil {
if r.StatusCodeResponses == nil {
r.StatusCodeResponses = map[int]Response{}
}
r.StatusCodeResponses[nk] = v
}
}
return nil
}

636
src/runtime/vendor/github.com/go-openapi/spec/schema.go generated vendored Normal file
View File

@@ -0,0 +1,636 @@
// 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 spec
import (
"encoding/json"
"fmt"
"net/url"
"strings"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// BooleanProperty creates a boolean property
func BooleanProperty() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}}
}
// BoolProperty creates a boolean property
func BoolProperty() *Schema { return BooleanProperty() }
// StringProperty creates a string property
func StringProperty() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
}
// CharProperty creates a string property
func CharProperty() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
}
// Float64Property creates a float64/double property
func Float64Property() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}}
}
// Float32Property creates a float32/float property
func Float32Property() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}}
}
// Int8Property creates an int8 property
func Int8Property() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}}
}
// Int16Property creates an int16 property
func Int16Property() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}}
}
// Int32Property creates an int32 property
func Int32Property() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}}
}
// Int64Property creates an int64 property
func Int64Property() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}
}
// StrFmtProperty creates a property for the named string format
func StrFmtProperty(format string) *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}}
}
// DateProperty creates a date property
func DateProperty() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}}
}
// DateTimeProperty creates a date time property
func DateTimeProperty() *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}}
}
// MapProperty creates a map property
func MapProperty(property *Schema) *Schema {
return &Schema{SchemaProps: SchemaProps{Type: []string{"object"}, AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}}
}
// RefProperty creates a ref property
func RefProperty(name string) *Schema {
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
}
// RefSchema creates a ref property
func RefSchema(name string) *Schema {
return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
}
// ArrayProperty creates an array property
func ArrayProperty(items *Schema) *Schema {
if items == nil {
return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}}
}
return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}}
}
// ComposedSchema creates a schema with allOf
func ComposedSchema(schemas ...Schema) *Schema {
s := new(Schema)
s.AllOf = schemas
return s
}
// SchemaURL represents a schema url
type SchemaURL string
// MarshalJSON marshal this to JSON
func (r SchemaURL) MarshalJSON() ([]byte, error) {
if r == "" {
return []byte("{}"), nil
}
v := map[string]interface{}{"$schema": string(r)}
return json.Marshal(v)
}
// UnmarshalJSON unmarshal this from JSON
func (r *SchemaURL) UnmarshalJSON(data []byte) error {
var v map[string]interface{}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
return r.fromMap(v)
}
func (r *SchemaURL) fromMap(v map[string]interface{}) error {
if v == nil {
return nil
}
if vv, ok := v["$schema"]; ok {
if str, ok := vv.(string); ok {
u, err := url.Parse(str)
if err != nil {
return err
}
*r = SchemaURL(u.String())
}
}
return nil
}
// type ExtraSchemaProps map[string]interface{}
// // JSONSchema represents a structure that is a json schema draft 04
// type JSONSchema struct {
// SchemaProps
// ExtraSchemaProps
// }
// // MarshalJSON marshal this to JSON
// func (s JSONSchema) MarshalJSON() ([]byte, error) {
// b1, err := json.Marshal(s.SchemaProps)
// if err != nil {
// return nil, err
// }
// b2, err := s.Ref.MarshalJSON()
// if err != nil {
// return nil, err
// }
// b3, err := s.Schema.MarshalJSON()
// if err != nil {
// return nil, err
// }
// b4, err := json.Marshal(s.ExtraSchemaProps)
// if err != nil {
// return nil, err
// }
// return swag.ConcatJSON(b1, b2, b3, b4), nil
// }
// // UnmarshalJSON marshal this from JSON
// func (s *JSONSchema) UnmarshalJSON(data []byte) error {
// var sch JSONSchema
// if err := json.Unmarshal(data, &sch.SchemaProps); err != nil {
// return err
// }
// if err := json.Unmarshal(data, &sch.Ref); err != nil {
// return err
// }
// if err := json.Unmarshal(data, &sch.Schema); err != nil {
// return err
// }
// if err := json.Unmarshal(data, &sch.ExtraSchemaProps); err != nil {
// return err
// }
// *s = sch
// return nil
// }
// SchemaProps describes a JSON schema (draft 4)
type SchemaProps struct {
ID string `json:"id,omitempty"`
Ref Ref `json:"-"`
Schema SchemaURL `json:"-"`
Description string `json:"description,omitempty"`
Type StringOrArray `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Title string `json:"title,omitempty"`
Default interface{} `json:"default,omitempty"`
Maximum *float64 `json:"maximum,omitempty"`
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
Minimum *float64 `json:"minimum,omitempty"`
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
MaxLength *int64 `json:"maxLength,omitempty"`
MinLength *int64 `json:"minLength,omitempty"`
Pattern string `json:"pattern,omitempty"`
MaxItems *int64 `json:"maxItems,omitempty"`
MinItems *int64 `json:"minItems,omitempty"`
UniqueItems bool `json:"uniqueItems,omitempty"`
MultipleOf *float64 `json:"multipleOf,omitempty"`
Enum []interface{} `json:"enum,omitempty"`
MaxProperties *int64 `json:"maxProperties,omitempty"`
MinProperties *int64 `json:"minProperties,omitempty"`
Required []string `json:"required,omitempty"`
Items *SchemaOrArray `json:"items,omitempty"`
AllOf []Schema `json:"allOf,omitempty"`
OneOf []Schema `json:"oneOf,omitempty"`
AnyOf []Schema `json:"anyOf,omitempty"`
Not *Schema `json:"not,omitempty"`
Properties map[string]Schema `json:"properties,omitempty"`
AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"`
PatternProperties map[string]Schema `json:"patternProperties,omitempty"`
Dependencies Dependencies `json:"dependencies,omitempty"`
AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"`
Definitions Definitions `json:"definitions,omitempty"`
}
// SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4)
type SwaggerSchemaProps struct {
Discriminator string `json:"discriminator,omitempty"`
ReadOnly bool `json:"readOnly,omitempty"`
XML *XMLObject `json:"xml,omitempty"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
Example interface{} `json:"example,omitempty"`
}
// Schema the schema object allows the definition of input and output data types.
// These types can be objects, but also primitives and arrays.
// This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/)
// and uses a predefined subset of it.
// On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
//
// For more information: http://goo.gl/8us55a#schemaObject
type Schema struct {
VendorExtensible
SchemaProps
SwaggerSchemaProps
ExtraProps map[string]interface{} `json:"-"`
}
// JSONLookup implements an interface to customize json pointer lookup
func (s Schema) JSONLookup(token string) (interface{}, error) {
if ex, ok := s.Extensions[token]; ok {
return &ex, nil
}
if ex, ok := s.ExtraProps[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(s.SchemaProps, token)
if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) {
return r, err
}
r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token)
return r, err
}
// WithID sets the id for this schema, allows for chaining
func (s *Schema) WithID(id string) *Schema {
s.ID = id
return s
}
// WithTitle sets the title for this schema, allows for chaining
func (s *Schema) WithTitle(title string) *Schema {
s.Title = title
return s
}
// WithDescription sets the description for this schema, allows for chaining
func (s *Schema) WithDescription(description string) *Schema {
s.Description = description
return s
}
// WithProperties sets the properties for this schema
func (s *Schema) WithProperties(schemas map[string]Schema) *Schema {
s.Properties = schemas
return s
}
// SetProperty sets a property on this schema
func (s *Schema) SetProperty(name string, schema Schema) *Schema {
if s.Properties == nil {
s.Properties = make(map[string]Schema)
}
s.Properties[name] = schema
return s
}
// WithAllOf sets the all of property
func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
s.AllOf = schemas
return s
}
// WithMaxProperties sets the max number of properties an object can have
func (s *Schema) WithMaxProperties(max int64) *Schema {
s.MaxProperties = &max
return s
}
// WithMinProperties sets the min number of properties an object must have
func (s *Schema) WithMinProperties(min int64) *Schema {
s.MinProperties = &min
return s
}
// Typed sets the type of this schema for a single value item
func (s *Schema) Typed(tpe, format string) *Schema {
s.Type = []string{tpe}
s.Format = format
return s
}
// AddType adds a type with potential format to the types for this schema
func (s *Schema) AddType(tpe, format string) *Schema {
s.Type = append(s.Type, tpe)
if format != "" {
s.Format = format
}
return s
}
// CollectionOf a fluent builder method for an array parameter
func (s *Schema) CollectionOf(items Schema) *Schema {
s.Type = []string{"array"}
s.Items = &SchemaOrArray{Schema: &items}
return s
}
// WithDefault sets the default value on this parameter
func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
s.Default = defaultValue
return s
}
// WithRequired flags this parameter as required
func (s *Schema) WithRequired(items ...string) *Schema {
s.Required = items
return s
}
// AddRequired adds field names to the required properties array
func (s *Schema) AddRequired(items ...string) *Schema {
s.Required = append(s.Required, items...)
return s
}
// WithMaxLength sets a max length value
func (s *Schema) WithMaxLength(max int64) *Schema {
s.MaxLength = &max
return s
}
// WithMinLength sets a min length value
func (s *Schema) WithMinLength(min int64) *Schema {
s.MinLength = &min
return s
}
// WithPattern sets a pattern value
func (s *Schema) WithPattern(pattern string) *Schema {
s.Pattern = pattern
return s
}
// WithMultipleOf sets a multiple of value
func (s *Schema) WithMultipleOf(number float64) *Schema {
s.MultipleOf = &number
return s
}
// WithMaximum sets a maximum number value
func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
s.Maximum = &max
s.ExclusiveMaximum = exclusive
return s
}
// WithMinimum sets a minimum number value
func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
s.Minimum = &min
s.ExclusiveMinimum = exclusive
return s
}
// WithEnum sets a the enum values (replace)
func (s *Schema) WithEnum(values ...interface{}) *Schema {
s.Enum = append([]interface{}{}, values...)
return s
}
// WithMaxItems sets the max items
func (s *Schema) WithMaxItems(size int64) *Schema {
s.MaxItems = &size
return s
}
// WithMinItems sets the min items
func (s *Schema) WithMinItems(size int64) *Schema {
s.MinItems = &size
return s
}
// UniqueValues dictates that this array can only have unique items
func (s *Schema) UniqueValues() *Schema {
s.UniqueItems = true
return s
}
// AllowDuplicates this array can have duplicates
func (s *Schema) AllowDuplicates() *Schema {
s.UniqueItems = false
return s
}
// AddToAllOf adds a schema to the allOf property
func (s *Schema) AddToAllOf(schemas ...Schema) *Schema {
s.AllOf = append(s.AllOf, schemas...)
return s
}
// WithDiscriminator sets the name of the discriminator field
func (s *Schema) WithDiscriminator(discriminator string) *Schema {
s.Discriminator = discriminator
return s
}
// AsReadOnly flags this schema as readonly
func (s *Schema) AsReadOnly() *Schema {
s.ReadOnly = true
return s
}
// AsWritable flags this schema as writeable (not read-only)
func (s *Schema) AsWritable() *Schema {
s.ReadOnly = false
return s
}
// WithExample sets the example for this schema
func (s *Schema) WithExample(example interface{}) *Schema {
s.Example = example
return s
}
// WithExternalDocs sets/removes the external docs for/from this schema.
// When you pass empty strings as params the external documents will be removed.
// When you pass non-empty string as one value then those values will be used on the external docs object.
// So when you pass a non-empty description, you should also pass the url and vice versa.
func (s *Schema) WithExternalDocs(description, url string) *Schema {
if description == "" && url == "" {
s.ExternalDocs = nil
return s
}
if s.ExternalDocs == nil {
s.ExternalDocs = &ExternalDocumentation{}
}
s.ExternalDocs.Description = description
s.ExternalDocs.URL = url
return s
}
// WithXMLName sets the xml name for the object
func (s *Schema) WithXMLName(name string) *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Name = name
return s
}
// WithXMLNamespace sets the xml namespace for the object
func (s *Schema) WithXMLNamespace(namespace string) *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Namespace = namespace
return s
}
// WithXMLPrefix sets the xml prefix for the object
func (s *Schema) WithXMLPrefix(prefix string) *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Prefix = prefix
return s
}
// AsXMLAttribute flags this object as xml attribute
func (s *Schema) AsXMLAttribute() *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Attribute = true
return s
}
// AsXMLElement flags this object as an xml node
func (s *Schema) AsXMLElement() *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Attribute = false
return s
}
// AsWrappedXML flags this object as wrapped, this is mostly useful for array types
func (s *Schema) AsWrappedXML() *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Wrapped = true
return s
}
// AsUnwrappedXML flags this object as an xml node
func (s *Schema) AsUnwrappedXML() *Schema {
if s.XML == nil {
s.XML = new(XMLObject)
}
s.XML.Wrapped = false
return s
}
// MarshalJSON marshal this to JSON
func (s Schema) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(s.SchemaProps)
if err != nil {
return nil, fmt.Errorf("schema props %v", err)
}
b2, err := json.Marshal(s.VendorExtensible)
if err != nil {
return nil, fmt.Errorf("vendor props %v", err)
}
b3, err := s.Ref.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("ref prop %v", err)
}
b4, err := s.Schema.MarshalJSON()
if err != nil {
return nil, fmt.Errorf("schema prop %v", err)
}
b5, err := json.Marshal(s.SwaggerSchemaProps)
if err != nil {
return nil, fmt.Errorf("common validations %v", err)
}
var b6 []byte
if s.ExtraProps != nil {
jj, err := json.Marshal(s.ExtraProps)
if err != nil {
return nil, fmt.Errorf("extra props %v", err)
}
b6 = jj
}
return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
}
// UnmarshalJSON marshal this from JSON
func (s *Schema) UnmarshalJSON(data []byte) error {
props := struct {
SchemaProps
SwaggerSchemaProps
}{}
if err := json.Unmarshal(data, &props); err != nil {
return err
}
sch := Schema{
SchemaProps: props.SchemaProps,
SwaggerSchemaProps: props.SwaggerSchemaProps,
}
var d map[string]interface{}
if err := json.Unmarshal(data, &d); err != nil {
return err
}
_ = sch.Ref.fromMap(d)
_ = sch.Schema.fromMap(d)
delete(d, "$ref")
delete(d, "$schema")
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
delete(d, pn)
}
for k, vv := range d {
lk := strings.ToLower(k)
if strings.HasPrefix(lk, "x-") {
if sch.Extensions == nil {
sch.Extensions = map[string]interface{}{}
}
sch.Extensions[k] = vv
continue
}
if sch.ExtraProps == nil {
sch.ExtraProps = map[string]interface{}{}
}
sch.ExtraProps[k] = vv
}
*s = sch
return nil
}

View File

@@ -0,0 +1,143 @@
// 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 spec
import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
const (
basic = "basic"
apiKey = "apiKey"
oauth2 = "oauth2"
implicit = "implicit"
password = "password"
application = "application"
accessCode = "accessCode"
)
// BasicAuth creates a basic auth security scheme
func BasicAuth() *SecurityScheme {
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: basic}}
}
// APIKeyAuth creates an api key auth security scheme
func APIKeyAuth(fieldName, valueSource string) *SecurityScheme {
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{Type: apiKey, Name: fieldName, In: valueSource}}
}
// OAuth2Implicit creates an implicit flow oauth2 security scheme
func OAuth2Implicit(authorizationURL string) *SecurityScheme {
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
Type: oauth2,
Flow: implicit,
AuthorizationURL: authorizationURL,
}}
}
// OAuth2Password creates a password flow oauth2 security scheme
func OAuth2Password(tokenURL string) *SecurityScheme {
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
Type: oauth2,
Flow: password,
TokenURL: tokenURL,
}}
}
// OAuth2Application creates an application flow oauth2 security scheme
func OAuth2Application(tokenURL string) *SecurityScheme {
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
Type: oauth2,
Flow: application,
TokenURL: tokenURL,
}}
}
// OAuth2AccessToken creates an access token flow oauth2 security scheme
func OAuth2AccessToken(authorizationURL, tokenURL string) *SecurityScheme {
return &SecurityScheme{SecuritySchemeProps: SecuritySchemeProps{
Type: oauth2,
Flow: accessCode,
AuthorizationURL: authorizationURL,
TokenURL: tokenURL,
}}
}
// SecuritySchemeProps describes a swagger security scheme in the securityDefinitions section
type SecuritySchemeProps struct {
Description string `json:"description,omitempty"`
Type string `json:"type"`
Name string `json:"name,omitempty"` // api key
In string `json:"in,omitempty"` // api key
Flow string `json:"flow,omitempty"` // oauth2
AuthorizationURL string `json:"authorizationUrl,omitempty"` // oauth2
TokenURL string `json:"tokenUrl,omitempty"` // oauth2
Scopes map[string]string `json:"scopes,omitempty"` // oauth2
}
// AddScope adds a scope to this security scheme
func (s *SecuritySchemeProps) AddScope(scope, description string) {
if s.Scopes == nil {
s.Scopes = make(map[string]string)
}
s.Scopes[scope] = description
}
// SecurityScheme allows the definition of a security scheme that can be used by the operations.
// Supported schemes are basic authentication, an API key (either as a header or as a query parameter)
// and OAuth2's common flows (implicit, password, application and access code).
//
// For more information: http://goo.gl/8us55a#securitySchemeObject
type SecurityScheme struct {
VendorExtensible
SecuritySchemeProps
}
// JSONLookup implements an interface to customize json pointer lookup
func (s SecurityScheme) JSONLookup(token string) (interface{}, error) {
if ex, ok := s.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(s.SecuritySchemeProps, token)
return r, err
}
// MarshalJSON marshal this to JSON
func (s SecurityScheme) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(s.SecuritySchemeProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(s.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON marshal this from JSON
func (s *SecurityScheme) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil {
return err
}
if err := json.Unmarshal(data, &s.VendorExtensible); err != nil {
return err
}
return nil
}

86
src/runtime/vendor/github.com/go-openapi/spec/spec.go generated vendored Normal file
View File

@@ -0,0 +1,86 @@
// 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 spec
import "encoding/json"
//go:generate curl -L --progress -o ./schemas/v2/schema.json http://swagger.io/v2/schema.json
//go:generate curl -L --progress -o ./schemas/jsonschema-draft-04.json http://json-schema.org/draft-04/schema
//go:generate go-bindata -pkg=spec -prefix=./schemas -ignore=.*\.md ./schemas/...
//go:generate perl -pi -e s,Json,JSON,g bindata.go
const (
// SwaggerSchemaURL the url for the swagger 2.0 schema to validate specs
SwaggerSchemaURL = "http://swagger.io/v2/schema.json#"
// JSONSchemaURL the url for the json schema schema
JSONSchemaURL = "http://json-schema.org/draft-04/schema#"
)
var (
jsonSchema *Schema
swaggerSchema *Schema
)
func init() {
jsonSchema = MustLoadJSONSchemaDraft04()
swaggerSchema = MustLoadSwagger20Schema()
}
// MustLoadJSONSchemaDraft04 panics when Swagger20Schema returns an error
func MustLoadJSONSchemaDraft04() *Schema {
d, e := JSONSchemaDraft04()
if e != nil {
panic(e)
}
return d
}
// JSONSchemaDraft04 loads the json schema document for json shema draft04
func JSONSchemaDraft04() (*Schema, error) {
b, err := Asset("jsonschema-draft-04.json")
if err != nil {
return nil, err
}
schema := new(Schema)
if err := json.Unmarshal(b, schema); err != nil {
return nil, err
}
return schema, nil
}
// MustLoadSwagger20Schema panics when Swagger20Schema returns an error
func MustLoadSwagger20Schema() *Schema {
d, e := Swagger20Schema()
if e != nil {
panic(e)
}
return d
}
// Swagger20Schema loads the swagger 2.0 schema from the embedded assets
func Swagger20Schema() (*Schema, error) {
b, err := Asset("v2/schema.json")
if err != nil {
return nil, err
}
schema := new(Schema)
if err := json.Unmarshal(b, schema); err != nil {
return nil, err
}
return schema, nil
}

View File

@@ -0,0 +1,318 @@
// 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 spec
import (
"encoding/json"
"fmt"
"strconv"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// Swagger this is the root document object for the API specification.
// It combines what previously was the Resource Listing and API Declaration (version 1.2 and earlier) together into one document.
//
// For more information: http://goo.gl/8us55a#swagger-object-
type Swagger struct {
VendorExtensible
SwaggerProps
}
// JSONLookup look up a value by the json property name
func (s Swagger) JSONLookup(token string) (interface{}, error) {
if ex, ok := s.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(s.SwaggerProps, token)
return r, err
}
// MarshalJSON marshals this swagger structure to json
func (s Swagger) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(s.SwaggerProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(s.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON unmarshals a swagger spec from json
func (s *Swagger) UnmarshalJSON(data []byte) error {
var sw Swagger
if err := json.Unmarshal(data, &sw.SwaggerProps); err != nil {
return err
}
if err := json.Unmarshal(data, &sw.VendorExtensible); err != nil {
return err
}
*s = sw
return nil
}
// SwaggerProps captures the top-level properties of an Api specification
type SwaggerProps struct {
ID string `json:"id,omitempty"`
Consumes []string `json:"consumes,omitempty"`
Produces []string `json:"produces,omitempty"`
Schemes []string `json:"schemes,omitempty"` // the scheme, when present must be from [http, https, ws, wss]
Swagger string `json:"swagger,omitempty"`
Info *Info `json:"info,omitempty"`
Host string `json:"host,omitempty"`
BasePath string `json:"basePath,omitempty"` // must start with a leading "/"
Paths *Paths `json:"paths"` // required
Definitions Definitions `json:"definitions,omitempty"`
Parameters map[string]Parameter `json:"parameters,omitempty"`
Responses map[string]Response `json:"responses,omitempty"`
SecurityDefinitions SecurityDefinitions `json:"securityDefinitions,omitempty"`
Security []map[string][]string `json:"security,omitempty"`
Tags []Tag `json:"tags,omitempty"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
}
// Dependencies represent a dependencies property
type Dependencies map[string]SchemaOrStringArray
// SchemaOrBool represents a schema or boolean value, is biased towards true for the boolean property
type SchemaOrBool struct {
Allows bool
Schema *Schema
}
// JSONLookup implements an interface to customize json pointer lookup
func (s SchemaOrBool) JSONLookup(token string) (interface{}, error) {
if token == "allows" {
return s.Allows, nil
}
r, _, err := jsonpointer.GetForToken(s.Schema, token)
return r, err
}
var jsTrue = []byte("true")
var jsFalse = []byte("false")
// MarshalJSON convert this object to JSON
func (s SchemaOrBool) MarshalJSON() ([]byte, error) {
if s.Schema != nil {
return json.Marshal(s.Schema)
}
if s.Schema == nil && !s.Allows {
return jsFalse, nil
}
return jsTrue, nil
}
// UnmarshalJSON converts this bool or schema object from a JSON structure
func (s *SchemaOrBool) UnmarshalJSON(data []byte) error {
var nw SchemaOrBool
if len(data) >= 4 {
if data[0] == '{' {
var sch Schema
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
nw.Schema = &sch
}
nw.Allows = !(data[0] == 'f' && data[1] == 'a' && data[2] == 'l' && data[3] == 's' && data[4] == 'e')
}
*s = nw
return nil
}
// SchemaOrStringArray represents a schema or a string array
type SchemaOrStringArray struct {
Schema *Schema
Property []string
}
// JSONLookup implements an interface to customize json pointer lookup
func (s SchemaOrStringArray) JSONLookup(token string) (interface{}, error) {
r, _, err := jsonpointer.GetForToken(s.Schema, token)
return r, err
}
// MarshalJSON converts this schema object or array into JSON structure
func (s SchemaOrStringArray) MarshalJSON() ([]byte, error) {
if len(s.Property) > 0 {
return json.Marshal(s.Property)
}
if s.Schema != nil {
return json.Marshal(s.Schema)
}
return []byte("null"), nil
}
// UnmarshalJSON converts this schema object or array from a JSON structure
func (s *SchemaOrStringArray) UnmarshalJSON(data []byte) error {
var first byte
if len(data) > 1 {
first = data[0]
}
var nw SchemaOrStringArray
if first == '{' {
var sch Schema
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
nw.Schema = &sch
}
if first == '[' {
if err := json.Unmarshal(data, &nw.Property); err != nil {
return err
}
}
*s = nw
return nil
}
// Definitions contains the models explicitly defined in this spec
// An object to hold data types that can be consumed and produced by operations.
// These data types can be primitives, arrays or models.
//
// For more information: http://goo.gl/8us55a#definitionsObject
type Definitions map[string]Schema
// SecurityDefinitions a declaration of the security schemes available to be used in the specification.
// This does not enforce the security schemes on the operations and only serves to provide
// the relevant details for each scheme.
//
// For more information: http://goo.gl/8us55a#securityDefinitionsObject
type SecurityDefinitions map[string]*SecurityScheme
// StringOrArray represents a value that can either be a string
// or an array of strings. Mainly here for serialization purposes
type StringOrArray []string
// Contains returns true when the value is contained in the slice
func (s StringOrArray) Contains(value string) bool {
for _, str := range s {
if str == value {
return true
}
}
return false
}
// JSONLookup implements an interface to customize json pointer lookup
func (s SchemaOrArray) JSONLookup(token string) (interface{}, error) {
if _, err := strconv.Atoi(token); err == nil {
r, _, err := jsonpointer.GetForToken(s.Schemas, token)
return r, err
}
r, _, err := jsonpointer.GetForToken(s.Schema, token)
return r, err
}
// UnmarshalJSON unmarshals this string or array object from a JSON array or JSON string
func (s *StringOrArray) UnmarshalJSON(data []byte) error {
var first byte
if len(data) > 1 {
first = data[0]
}
if first == '[' {
var parsed []string
if err := json.Unmarshal(data, &parsed); err != nil {
return err
}
*s = StringOrArray(parsed)
return nil
}
var single interface{}
if err := json.Unmarshal(data, &single); err != nil {
return err
}
if single == nil {
return nil
}
switch single.(type) {
case string:
*s = StringOrArray([]string{single.(string)})
return nil
default:
return fmt.Errorf("only string or array is allowed, not %T", single)
}
}
// MarshalJSON converts this string or array to a JSON array or JSON string
func (s StringOrArray) MarshalJSON() ([]byte, error) {
if len(s) == 1 {
return json.Marshal([]string(s)[0])
}
return json.Marshal([]string(s))
}
// SchemaOrArray represents a value that can either be a Schema
// or an array of Schema. Mainly here for serialization purposes
type SchemaOrArray struct {
Schema *Schema
Schemas []Schema
}
// Len returns the number of schemas in this property
func (s SchemaOrArray) Len() int {
if s.Schema != nil {
return 1
}
return len(s.Schemas)
}
// ContainsType returns true when one of the schemas is of the specified type
func (s *SchemaOrArray) ContainsType(name string) bool {
if s.Schema != nil {
return s.Schema.Type != nil && s.Schema.Type.Contains(name)
}
return false
}
// MarshalJSON converts this schema object or array into JSON structure
func (s SchemaOrArray) MarshalJSON() ([]byte, error) {
if len(s.Schemas) > 0 {
return json.Marshal(s.Schemas)
}
return json.Marshal(s.Schema)
}
// UnmarshalJSON converts this schema object or array from a JSON structure
func (s *SchemaOrArray) UnmarshalJSON(data []byte) error {
var nw SchemaOrArray
var first byte
if len(data) > 1 {
first = data[0]
}
if first == '{' {
var sch Schema
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
nw.Schema = &sch
}
if first == '[' {
if err := json.Unmarshal(data, &nw.Schemas); err != nil {
return err
}
}
*s = nw
return nil
}
// vim:set ft=go noet sts=2 sw=2 ts=2:

74
src/runtime/vendor/github.com/go-openapi/spec/tag.go generated vendored Normal file
View File

@@ -0,0 +1,74 @@
// 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 spec
import (
"encoding/json"
"github.com/go-openapi/jsonpointer"
"github.com/go-openapi/swag"
)
// TagProps describe a tag entry in the top level tags section of a swagger spec
type TagProps struct {
Description string `json:"description,omitempty"`
Name string `json:"name,omitempty"`
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
}
// NewTag creates a new tag
func NewTag(name, description string, externalDocs *ExternalDocumentation) Tag {
return Tag{TagProps: TagProps{description, name, externalDocs}}
}
// Tag allows adding meta data to a single tag that is used by the [Operation Object](http://goo.gl/8us55a#operationObject).
// It is not mandatory to have a Tag Object per tag used there.
//
// For more information: http://goo.gl/8us55a#tagObject
type Tag struct {
VendorExtensible
TagProps
}
// JSONLookup implements an interface to customize json pointer lookup
func (t Tag) JSONLookup(token string) (interface{}, error) {
if ex, ok := t.Extensions[token]; ok {
return &ex, nil
}
r, _, err := jsonpointer.GetForToken(t.TagProps, token)
return r, err
}
// MarshalJSON marshal this to JSON
func (t Tag) MarshalJSON() ([]byte, error) {
b1, err := json.Marshal(t.TagProps)
if err != nil {
return nil, err
}
b2, err := json.Marshal(t.VendorExtensible)
if err != nil {
return nil, err
}
return swag.ConcatJSON(b1, b2), nil
}
// UnmarshalJSON marshal this from JSON
func (t *Tag) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &t.TagProps); err != nil {
return err
}
return json.Unmarshal(data, &t.VendorExtensible)
}

View File

@@ -0,0 +1,68 @@
// 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 spec
// XMLObject a metadata object that allows for more fine-tuned XML model definitions.
//
// For more information: http://goo.gl/8us55a#xmlObject
type XMLObject struct {
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
Prefix string `json:"prefix,omitempty"`
Attribute bool `json:"attribute,omitempty"`
Wrapped bool `json:"wrapped,omitempty"`
}
// WithName sets the xml name for the object
func (x *XMLObject) WithName(name string) *XMLObject {
x.Name = name
return x
}
// WithNamespace sets the xml namespace for the object
func (x *XMLObject) WithNamespace(namespace string) *XMLObject {
x.Namespace = namespace
return x
}
// WithPrefix sets the xml prefix for the object
func (x *XMLObject) WithPrefix(prefix string) *XMLObject {
x.Prefix = prefix
return x
}
// AsAttribute flags this object as xml attribute
func (x *XMLObject) AsAttribute() *XMLObject {
x.Attribute = true
return x
}
// AsElement flags this object as an xml node
func (x *XMLObject) AsElement() *XMLObject {
x.Attribute = false
return x
}
// AsWrapped flags this object as wrapped, this is mostly useful for array types
func (x *XMLObject) AsWrapped() *XMLObject {
x.Wrapped = true
return x
}
// AsUnwrapped flags this object as an xml node
func (x *XMLObject) AsUnwrapped() *XMLObject {
x.Wrapped = false
return x
}

202
src/runtime/vendor/github.com/go-openapi/strfmt/LICENSE generated vendored Normal file
View 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.

127
src/runtime/vendor/github.com/go-openapi/strfmt/bson.go generated vendored Normal file
View File

@@ -0,0 +1,127 @@
// 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 strfmt
import (
"database/sql/driver"
"errors"
"fmt"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
)
func init() {
var id ObjectId
// register this format in the default registry
Default.Add("bsonobjectid", &id, IsBSONObjectID)
}
// IsBSONObjectID returns true when the string is a valid BSON.ObjectId
func IsBSONObjectID(str string) bool {
return bson.IsObjectIdHex(str)
}
// ObjectId represents a BSON object ID (alias to github.com/globalsign/mgo/bson.ObjectId)
//
// swagger:strfmt bsonobjectid
type ObjectId bson.ObjectId
// NewObjectId creates a ObjectId from a Hex String
func NewObjectId(hex string) ObjectId {
return ObjectId(bson.ObjectIdHex(hex))
}
// MarshalText turns this instance into text
func (id *ObjectId) MarshalText() ([]byte, error) {
return []byte(bson.ObjectId(*id).Hex()), nil
}
// UnmarshalText hydrates this instance from text
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
*id = ObjectId(bson.ObjectIdHex(string(data)))
return nil
}
// Scan read a value from a database driver
func (id *ObjectId) Scan(raw interface{}) error {
var data []byte
switch v := raw.(type) {
case []byte:
data = v
case string:
data = []byte(v)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v", v)
}
return id.UnmarshalText(data)
}
// Value converts a value to a database driver value
func (id *ObjectId) Value() (driver.Value, error) {
return driver.Value(string(*id)), nil
}
func (id *ObjectId) String() string {
return string(*id)
}
// MarshalJSON returns the ObjectId as JSON
func (id *ObjectId) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
id.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the ObjectId to a easyjson.Writer
func (id *ObjectId) MarshalEasyJSON(w *jwriter.Writer) {
w.String(bson.ObjectId(*id).Hex())
}
// UnmarshalJSON sets the ObjectId from JSON
func (id *ObjectId) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
id.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the ObjectId from a easyjson.Lexer
func (id *ObjectId) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
*id = NewObjectId(data)
}
}
// GetBSON returns the hex representation of the ObjectId as a bson.M{} map.
func (id *ObjectId) GetBSON() (interface{}, error) {
return bson.M{"data": bson.ObjectId(*id).Hex()}, nil
}
// SetBSON sets the ObjectId from raw bson data
func (id *ObjectId) SetBSON(raw bson.Raw) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
return err
}
if data, ok := m["data"].(string); ok {
*id = NewObjectId(data)
return nil
}
return errors.New("couldn't unmarshal bson raw value as ObjectId")
}

150
src/runtime/vendor/github.com/go-openapi/strfmt/date.go generated vendored Normal file
View File

@@ -0,0 +1,150 @@
// 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 strfmt
import (
"database/sql/driver"
"errors"
"fmt"
"time"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
)
func init() {
d := Date{}
// register this format in the default registry
Default.Add("date", &d, IsDate)
}
// IsDate returns true when the string is a valid date
func IsDate(str string) bool {
_, err := time.Parse(RFC3339FullDate, str)
return err == nil
}
const (
// RFC3339FullDate represents a full-date as specified by RFC3339
// See: http://goo.gl/xXOvVd
RFC3339FullDate = "2006-01-02"
)
// Date represents a date from the API
//
// swagger:strfmt date
type Date time.Time
// String converts this date into a string
func (d Date) String() string {
return time.Time(d).Format(RFC3339FullDate)
}
// UnmarshalText parses a text representation into a date type
func (d *Date) UnmarshalText(text []byte) error {
if len(text) == 0 {
return nil
}
dd, err := time.Parse(RFC3339FullDate, string(text))
if err != nil {
return err
}
*d = Date(dd)
return nil
}
// MarshalText serializes this date type to string
func (d Date) MarshalText() ([]byte, error) {
return []byte(d.String()), nil
}
// Scan scans a Date value from database driver type.
func (d *Date) Scan(raw interface{}) error {
switch v := raw.(type) {
case []byte:
return d.UnmarshalText(v)
case string:
return d.UnmarshalText([]byte(v))
case time.Time:
*d = Date(v)
return nil
case nil:
*d = Date{}
return nil
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Date from: %#v", v)
}
}
// Value converts Date to a primitive value ready to written to a database.
func (d Date) Value() (driver.Value, error) {
return driver.Value(d.String()), nil
}
// MarshalJSON returns the Date as JSON
func (d Date) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
d.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the Date to a easyjson.Writer
func (d Date) MarshalEasyJSON(w *jwriter.Writer) {
w.String(time.Time(d).Format(RFC3339FullDate))
}
// UnmarshalJSON sets the Date from JSON
func (d *Date) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
}
l := jlexer.Lexer{Data: data}
d.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the Date from a easyjson.Lexer
func (d *Date) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
tt, err := time.Parse(RFC3339FullDate, data)
if err != nil {
in.AddError(err)
return
}
*d = Date(tt)
}
}
// GetBSON returns the Date as a bson.M{} map.
func (d *Date) GetBSON() (interface{}, error) {
return bson.M{"data": d.String()}, nil
}
// SetBSON sets the Date from raw bson data
func (d *Date) SetBSON(raw bson.Raw) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
return err
}
if data, ok := m["data"].(string); ok {
rd, err := time.Parse(RFC3339FullDate, data)
*d = Date(rd)
return err
}
return errors.New("couldn't unmarshal bson raw value as Date")
}

File diff suppressed because it is too large Load Diff

18
src/runtime/vendor/github.com/go-openapi/strfmt/doc.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
// 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 strfmt contains custom string formats
//
// TODO: add info on how to define and register a custom format
package strfmt

View File

@@ -0,0 +1,203 @@
// 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 strfmt
import (
"database/sql/driver"
"errors"
"fmt"
"regexp"
"strconv"
"strings"
"time"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
)
func init() {
d := Duration(0)
// register this format in the default registry
Default.Add("duration", &d, IsDuration)
}
var (
timeUnits = [][]string{
{"ns", "nano"},
{"us", "µs", "micro"},
{"ms", "milli"},
{"s", "sec"},
{"m", "min"},
{"h", "hr", "hour"},
{"d", "day"},
{"w", "wk", "week"},
}
timeMultiplier = map[string]time.Duration{
"ns": time.Nanosecond,
"us": time.Microsecond,
"ms": time.Millisecond,
"s": time.Second,
"m": time.Minute,
"h": time.Hour,
"d": 24 * time.Hour,
"w": 7 * 24 * time.Hour,
}
durationMatcher = regexp.MustCompile(`((\d+)\s*([A-Za-zµ]+))`)
)
// IsDuration returns true if the provided string is a valid duration
func IsDuration(str string) bool {
_, err := ParseDuration(str)
return err == nil
}
// Duration represents a duration
//
// Duration stores a period of time as a nanosecond count, with the largest
// repesentable duration being approximately 290 years.
//
// swagger:strfmt duration
type Duration time.Duration
// MarshalText turns this instance into text
func (d Duration) MarshalText() ([]byte, error) {
return []byte(time.Duration(d).String()), nil
}
// UnmarshalText hydrates this instance from text
func (d *Duration) UnmarshalText(data []byte) error { // validation is performed later on
dd, err := ParseDuration(string(data))
if err != nil {
return err
}
*d = Duration(dd)
return nil
}
// ParseDuration parses a duration from a string, compatible with scala duration syntax
func ParseDuration(cand string) (time.Duration, error) {
if dur, err := time.ParseDuration(cand); err == nil {
return dur, nil
}
var dur time.Duration
ok := false
for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) {
factor, err := strconv.Atoi(match[2]) // converts string to int
if err != nil {
return 0, err
}
unit := strings.ToLower(strings.TrimSpace(match[3]))
for _, variants := range timeUnits {
last := len(variants) - 1
multiplier := timeMultiplier[variants[0]]
for i, variant := range variants {
if (last == i && strings.HasPrefix(unit, variant)) || strings.EqualFold(variant, unit) {
ok = true
dur += (time.Duration(factor) * multiplier)
}
}
}
}
if ok {
return dur, nil
}
return 0, fmt.Errorf("unable to parse %s as duration", cand)
}
// Scan reads a Duration value from database driver type.
func (d *Duration) Scan(raw interface{}) error {
switch v := raw.(type) {
// TODO: case []byte: // ?
case int64:
*d = Duration(v)
case float64:
*d = Duration(int64(v))
case nil:
*d = Duration(0)
default:
return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v)
}
return nil
}
// Value converts Duration to a primitive value ready to be written to a database.
func (d Duration) Value() (driver.Value, error) {
return driver.Value(int64(d)), nil
}
// String converts this duration to a string
func (d Duration) String() string {
return time.Duration(d).String()
}
// MarshalJSON returns the Duration as JSON
func (d Duration) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
d.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the Duration to a easyjson.Writer
func (d Duration) MarshalEasyJSON(w *jwriter.Writer) {
w.String(time.Duration(d).String())
}
// UnmarshalJSON sets the Duration from JSON
func (d *Duration) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
d.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the Duration from a easyjson.Lexer
func (d *Duration) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
tt, err := ParseDuration(data)
if err != nil {
in.AddError(err)
return
}
*d = Duration(tt)
}
}
// GetBSON returns the Duration a bson.M{} map.
func (d *Duration) GetBSON() (interface{}, error) {
return bson.M{"data": int64(*d)}, nil
}
// SetBSON sets the Duration from raw bson data
func (d *Duration) SetBSON(raw bson.Raw) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
return err
}
if data, ok := m["data"].(int64); ok {
*d = Duration(data)
return nil
}
return errors.New("couldn't unmarshal bson raw value as Duration")
}

Some files were not shown because too many files have changed in this diff Show More