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 15package spec 16 17import ( 18 "encoding/json" 19 "net/http" 20 "os" 21 "path/filepath" 22 23 "github.com/go-openapi/jsonreference" 24) 25 26// Refable is a struct for things that accept a $ref property 27type Refable struct { 28 Ref Ref 29} 30 31// MarshalJSON marshals the ref to json 32func (r Refable) MarshalJSON() ([]byte, error) { 33 return r.Ref.MarshalJSON() 34} 35 36// UnmarshalJSON unmarshalss the ref from json 37func (r *Refable) UnmarshalJSON(d []byte) error { 38 return json.Unmarshal(d, &r.Ref) 39} 40 41// Ref represents a json reference that is potentially resolved 42type Ref struct { 43 jsonreference.Ref 44} 45 46// RemoteURI gets the remote uri part of the ref 47func (r *Ref) RemoteURI() string { 48 if r.String() == "" { 49 return r.String() 50 } 51 52 u := *r.GetURL() 53 u.Fragment = "" 54 return u.String() 55} 56 57// IsValidURI returns true when the url the ref points to can be found 58func (r *Ref) IsValidURI(basepaths ...string) bool { 59 if r.String() == "" { 60 return true 61 } 62 63 v := r.RemoteURI() 64 if v == "" { 65 return true 66 } 67 68 if r.HasFullURL { 69 rr, err := http.Get(v) 70 if err != nil { 71 return false 72 } 73 74 return rr.StatusCode/100 == 2 75 } 76 77 if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) { 78 return false 79 } 80 81 // check for local file 82 pth := v 83 if r.HasURLPathOnly { 84 base := "." 85 if len(basepaths) > 0 { 86 base = filepath.Dir(filepath.Join(basepaths...)) 87 } 88 p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth))) 89 if e != nil { 90 return false 91 } 92 pth = p 93 } 94 95 fi, err := os.Stat(filepath.ToSlash(pth)) 96 if err != nil { 97 return false 98 } 99 100 return !fi.IsDir() 101} 102 103// Inherits creates a new reference from a parent and a child 104// If the child cannot inherit from the parent, an error is returned 105func (r *Ref) Inherits(child Ref) (*Ref, error) { 106 ref, err := r.Ref.Inherits(child.Ref) 107 if err != nil { 108 return nil, err 109 } 110 return &Ref{Ref: *ref}, nil 111} 112 113// NewRef creates a new instance of a ref object 114// returns an error when the reference uri is an invalid uri 115func NewRef(refURI string) (Ref, error) { 116 ref, err := jsonreference.New(refURI) 117 if err != nil { 118 return Ref{}, err 119 } 120 return Ref{Ref: ref}, nil 121} 122 123// MustCreateRef creates a ref object but panics when refURI is invalid. 124// Use the NewRef method for a version that returns an error. 125func MustCreateRef(refURI string) Ref { 126 return Ref{Ref: jsonreference.MustCreateRef(refURI)} 127} 128 129// MarshalJSON marshals this ref into a JSON object 130func (r Ref) MarshalJSON() ([]byte, error) { 131 str := r.String() 132 if str == "" { 133 if r.IsRoot() { 134 return []byte(`{"$ref":""}`), nil 135 } 136 return []byte("{}"), nil 137 } 138 v := map[string]interface{}{"$ref": str} 139 return json.Marshal(v) 140} 141 142// UnmarshalJSON unmarshals this ref from a JSON object 143func (r *Ref) UnmarshalJSON(d []byte) error { 144 var v map[string]interface{} 145 if err := json.Unmarshal(d, &v); err != nil { 146 return err 147 } 148 return r.fromMap(v) 149} 150 151func (r *Ref) fromMap(v map[string]interface{}) error { 152 if v == nil { 153 return nil 154 } 155 156 if vv, ok := v["$ref"]; ok { 157 if str, ok := vv.(string); ok { 158 ref, err := jsonreference.New(str) 159 if err != nil { 160 return err 161 } 162 *r = Ref{Ref: ref} 163 } 164 } 165 166 return nil 167} 168