-
-
Notifications
You must be signed in to change notification settings - Fork 429
/
loader_uri_reader.go
104 lines (96 loc) · 3.23 KB
/
loader_uri_reader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package openapi3
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path/filepath"
)
// ReadFromURIFunc defines a function which reads the contents of a resource
// located at a URI.
type ReadFromURIFunc func(loader *Loader, url *url.URL) ([]byte, error)
// ErrURINotSupported indicates the ReadFromURIFunc does not know how to handle a
// given URI.
var ErrURINotSupported = errors.New("unsupported URI")
// ReadFromURIs returns a ReadFromURIFunc which tries to read a URI using the
// given reader functions, in the same order. If a reader function does not
// support the URI and returns ErrURINotSupported, the next function is checked
// until a match is found, or the URI is not supported by any.
func ReadFromURIs(readers ...ReadFromURIFunc) ReadFromURIFunc {
return func(loader *Loader, url *url.URL) ([]byte, error) {
for i := range readers {
buf, err := readers[i](loader, url)
if err == ErrURINotSupported {
continue
} else if err != nil {
return nil, err
}
return buf, nil
}
return nil, ErrURINotSupported
}
}
// DefaultReadFromURI returns a caching ReadFromURIFunc which can read remote
// HTTP URIs and local file URIs.
var DefaultReadFromURI = URIMapCache(ReadFromURIs(ReadFromHTTP(http.DefaultClient), ReadFromFile))
// ReadFromHTTP returns a ReadFromURIFunc which uses the given http.Client to
// read the contents from a remote HTTP URI. This client may be customized to
// implement timeouts, RFC 7234 caching, etc.
func ReadFromHTTP(cl *http.Client) ReadFromURIFunc {
return func(loader *Loader, location *url.URL) ([]byte, error) {
if location.Scheme == "" || location.Host == "" {
return nil, ErrURINotSupported
}
req, err := http.NewRequest("GET", location.String(), nil)
if err != nil {
return nil, err
}
resp, err := cl.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode > 399 {
return nil, fmt.Errorf("error loading %q: request returned status code %d", location.String(), resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
}
// ReadFromFile is a ReadFromURIFunc which reads local file URIs.
func ReadFromFile(loader *Loader, location *url.URL) ([]byte, error) {
if location.Host != "" {
return nil, ErrURINotSupported
}
if location.Scheme != "" && location.Scheme != "file" {
return nil, ErrURINotSupported
}
return ioutil.ReadFile(location.Path)
}
// URIMapCache returns a ReadFromURIFunc that caches the contents read from URI
// locations in a simple map. This cache implementation is suitable for
// short-lived processes such as command-line tools which process OpenAPI
// documents.
func URIMapCache(reader ReadFromURIFunc) ReadFromURIFunc {
cache := map[string][]byte{}
return func(loader *Loader, location *url.URL) (buf []byte, err error) {
if location.Scheme == "" || location.Scheme == "file" {
if !filepath.IsAbs(location.Path) {
// Do not cache relative file paths; this can cause trouble if
// the current working directory changes when processing
// multiple top-level documents.
return reader(loader, location)
}
}
uri := location.String()
var ok bool
if buf, ok = cache[uri]; ok {
return
}
if buf, err = reader(loader, location); err != nil {
return
}
cache[uri] = buf
return
}
}