k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/spec/ref.go (about) 1 // Copyright 2015 go-swagger maintainers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package spec 16 17 import ( 18 "encoding/json" 19 "net/http" 20 "os" 21 "path/filepath" 22 23 "github.com/go-openapi/jsonreference" 24 25 "k8s.io/kube-openapi/pkg/internal" 26 ) 27 28 // Refable is a struct for things that accept a $ref property 29 type Refable struct { 30 Ref Ref 31 } 32 33 // MarshalJSON marshals the ref to json 34 func (r Refable) MarshalJSON() ([]byte, error) { 35 return r.Ref.MarshalJSON() 36 } 37 38 // UnmarshalJSON unmarshalss the ref from json 39 func (r *Refable) UnmarshalJSON(d []byte) error { 40 return json.Unmarshal(d, &r.Ref) 41 } 42 43 // Ref represents a json reference that is potentially resolved 44 type Ref struct { 45 jsonreference.Ref 46 } 47 48 // RemoteURI gets the remote uri part of the ref 49 func (r *Ref) RemoteURI() string { 50 if r.String() == "" { 51 return r.String() 52 } 53 54 u := *r.GetURL() 55 u.Fragment = "" 56 return u.String() 57 } 58 59 // IsValidURI returns true when the url the ref points to can be found 60 func (r *Ref) IsValidURI(basepaths ...string) bool { 61 if r.String() == "" { 62 return true 63 } 64 65 v := r.RemoteURI() 66 if v == "" { 67 return true 68 } 69 70 if r.HasFullURL { 71 rr, err := http.Get(v) 72 if err != nil { 73 return false 74 } 75 76 return rr.StatusCode/100 == 2 77 } 78 79 if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) { 80 return false 81 } 82 83 // check for local file 84 pth := v 85 if r.HasURLPathOnly { 86 base := "." 87 if len(basepaths) > 0 { 88 base = filepath.Dir(filepath.Join(basepaths...)) 89 } 90 p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth))) 91 if e != nil { 92 return false 93 } 94 pth = p 95 } 96 97 fi, err := os.Stat(filepath.ToSlash(pth)) 98 if err != nil { 99 return false 100 } 101 102 return !fi.IsDir() 103 } 104 105 // Inherits creates a new reference from a parent and a child 106 // If the child cannot inherit from the parent, an error is returned 107 func (r *Ref) Inherits(child Ref) (*Ref, error) { 108 ref, err := r.Ref.Inherits(child.Ref) 109 if err != nil { 110 return nil, err 111 } 112 return &Ref{Ref: *ref}, nil 113 } 114 115 // NewRef creates a new instance of a ref object 116 // returns an error when the reference uri is an invalid uri 117 func NewRef(refURI string) (Ref, error) { 118 ref, err := jsonreference.New(refURI) 119 if err != nil { 120 return Ref{}, err 121 } 122 return Ref{Ref: ref}, nil 123 } 124 125 // MustCreateRef creates a ref object but panics when refURI is invalid. 126 // Use the NewRef method for a version that returns an error. 127 func MustCreateRef(refURI string) Ref { 128 return Ref{Ref: jsonreference.MustCreateRef(refURI)} 129 } 130 131 // MarshalJSON marshals this ref into a JSON object 132 func (r Ref) MarshalJSON() ([]byte, error) { 133 str := r.String() 134 if str == "" { 135 if r.IsRoot() { 136 return []byte(`{"$ref":""}`), nil 137 } 138 return []byte("{}"), nil 139 } 140 v := map[string]interface{}{"$ref": str} 141 return json.Marshal(v) 142 } 143 144 // UnmarshalJSON unmarshals this ref from a JSON object 145 func (r *Ref) UnmarshalJSON(d []byte) error { 146 var v map[string]interface{} 147 if err := json.Unmarshal(d, &v); err != nil { 148 return err 149 } 150 return r.fromMap(v) 151 } 152 153 func (r *Ref) fromMap(v map[string]interface{}) error { 154 return internal.JSONRefFromMap(&r.Ref, v) 155 }