From d97981ecc9929df01da0cce6cbbcea940202f643 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Mon, 3 Dec 2018 21:32:43 -0500 Subject: Support subpaths for http datasources (#442) * bug: subpaths were ignored in http datasources Signed-off-by: Dave Henderson * fixup! bug: subpaths were ignored in http datasources --- data/datasource_http.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 data/datasource_http.go (limited to 'data/datasource_http.go') diff --git a/data/datasource_http.go b/data/datasource_http.go new file mode 100644 index 00000000..5424fbd0 --- /dev/null +++ b/data/datasource_http.go @@ -0,0 +1,100 @@ +package data + +import ( + "io/ioutil" + "mime" + "net/http" + "net/url" + "strings" + "time" + + "github.com/pkg/errors" +) + +func buildURL(base *url.URL, args ...string) (*url.URL, error) { + if len(args) == 0 { + return base, nil + } + p, err := url.Parse(args[0]) + if err != nil { + return nil, errors.Wrapf(err, "bad sub-path %s", args[0]) + } + return base.ResolveReference(p), nil +} + +func readHTTP(source *Source, args ...string) ([]byte, error) { + if source.hc == nil { + source.hc = &http.Client{Timeout: time.Second * 5} + } + u, err := buildURL(source.URL, args...) + if err != nil { + return nil, err + } + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + req.Header = source.header + res, err := source.hc.Do(req) + if err != nil { + return nil, err + } + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + err = res.Body.Close() + if err != nil { + return nil, err + } + if res.StatusCode != 200 { + err := errors.Errorf("Unexpected HTTP status %d on GET from %s: %s", res.StatusCode, source.URL, string(body)) + return nil, err + } + ctypeHdr := res.Header.Get("Content-Type") + if ctypeHdr != "" { + mediatype, _, e := mime.ParseMediaType(ctypeHdr) + if e != nil { + return nil, e + } + source.mediaType = mediatype + } + return body, nil +} + +func parseHeaderArgs(headerArgs []string) (map[string]http.Header, error) { + headers := make(map[string]http.Header) + for _, v := range headerArgs { + ds, name, value, err := splitHeaderArg(v) + if err != nil { + return nil, err + } + if _, ok := headers[ds]; !ok { + headers[ds] = make(http.Header) + } + headers[ds][name] = append(headers[ds][name], strings.TrimSpace(value)) + } + return headers, nil +} + +func splitHeaderArg(arg string) (datasourceAlias, name, value string, err error) { + parts := strings.SplitN(arg, "=", 2) + if len(parts) != 2 { + err = errors.Errorf("Invalid datasource-header option '%s'", arg) + return "", "", "", err + } + datasourceAlias = parts[0] + name, value, err = splitHeader(parts[1]) + return datasourceAlias, name, value, err +} + +func splitHeader(header string) (name, value string, err error) { + parts := strings.SplitN(header, ":", 2) + if len(parts) != 2 { + err = errors.Errorf("Invalid HTTP Header format '%s'", header) + return "", "", err + } + name = http.CanonicalHeaderKey(parts[0]) + value = parts[1] + return name, value, nil +} -- cgit v1.2.3