cmd/go/internal/web2: second web helper library
diff --git a/vendor/cmd/go/internal/web2/web.go b/vendor/cmd/go/internal/web2/web.go
new file mode 100644
index 0000000..0a7b8de
--- /dev/null
+++ b/vendor/cmd/go/internal/web2/web.go
@@ -0,0 +1,255 @@
+// Copyright 2018 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.
+
+package web2
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime/debug"
+ "strings"
+ "sync"
+)
+
+var TraceGET = false
+var webstack = false
+
+func init() {
+ flag.BoolVar(&TraceGET, "webtrace", TraceGET, "trace GET requests")
+ flag.BoolVar(&webstack, "webstack", webstack, "print stack for GET requests")
+}
+
+type netrcLine struct {
+ machine string
+ login string
+ password string
+}
+
+var netrcOnce sync.Once
+var netrc []netrcLine
+
+func parseNetrc(data string) []netrcLine {
+ var nrc []netrcLine
+ var l netrcLine
+ for _, line := range strings.Split(string(data), "\n") {
+ f := strings.Fields(line)
+ for i := 0; i < len(f)-1; i += 2 {
+ switch f[i] {
+ case "machine":
+ l.machine = f[i+1]
+ case "login":
+ l.login = f[i+1]
+ case "password":
+ l.password = f[i+1]
+ }
+ }
+ if l.machine != "" && l.login != "" && l.password != "" {
+ nrc = append(nrc, l)
+ l = netrcLine{}
+ }
+ }
+ return nrc
+}
+
+func readNetrc() {
+ data, err := ioutil.ReadFile(filepath.Join(os.Getenv("HOME"), ".netrc"))
+ if err != nil {
+ return
+ }
+ netrc = parseNetrc(string(data))
+}
+
+type getState struct {
+ req *http.Request
+ resp *http.Response
+ body io.ReadCloser
+ non200ok bool
+}
+
+type Option interface {
+ option(*getState) error
+}
+
+func Non200OK() Option {
+ return optionFunc(func(g *getState) error {
+ g.non200ok = true
+ return nil
+ })
+}
+
+type optionFunc func(*getState) error
+
+func (f optionFunc) option(g *getState) error {
+ return f(g)
+}
+
+func DecodeJSON(dst interface{}) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ return json.NewDecoder(g.body).Decode(dst)
+ }
+ return nil
+ })
+}
+
+func ReadAllBody(body *[]byte) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ var err error
+ *body, err = ioutil.ReadAll(g.body)
+ return err
+ }
+ return nil
+ })
+}
+
+func Body(body *io.ReadCloser) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ *body = g.body
+ g.body = nil
+ }
+ return nil
+ })
+}
+
+func Header(hdr *http.Header) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ *hdr = CopyHeader(g.resp.Header)
+ }
+ return nil
+ })
+}
+
+func CopyHeader(hdr http.Header) http.Header {
+ if hdr == nil {
+ return nil
+ }
+ h2 := make(http.Header)
+ for k, v := range hdr {
+ v2 := make([]string, len(v))
+ copy(v2, v)
+ h2[k] = v2
+ }
+ return h2
+}
+
+var cache struct {
+ mu sync.Mutex
+ byURL map[string]*cacheEntry
+}
+
+type cacheEntry struct {
+ mu sync.Mutex
+ resp *http.Response
+ body []byte
+}
+
+var httpDo = http.DefaultClient.Do
+
+func SetHTTPDoForTesting(do func(*http.Request) (*http.Response, error)) {
+ if do == nil {
+ do = http.DefaultClient.Do
+ }
+ httpDo = do
+}
+
+func Get(url string, options ...Option) error {
+ if TraceGET || webstack {
+ println("GET", url)
+ if webstack {
+ println(string(debug.Stack()))
+ }
+ }
+
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return err
+ }
+
+ netrcOnce.Do(readNetrc)
+ for _, l := range netrc {
+ if l.machine == req.URL.Host {
+ req.SetBasicAuth(l.login, l.password)
+ break
+ }
+ }
+
+ g := &getState{req: req}
+ for _, o := range options {
+ if err := o.option(g); err != nil {
+ return err
+ }
+ }
+
+ cache.mu.Lock()
+ e := cache.byURL[url]
+ if e == nil {
+ e = new(cacheEntry)
+ if !strings.HasPrefix(url, "file:") {
+ if cache.byURL == nil {
+ cache.byURL = make(map[string]*cacheEntry)
+ }
+ cache.byURL[url] = e
+ }
+ }
+ cache.mu.Unlock()
+
+ e.mu.Lock()
+ if strings.HasPrefix(url, "file:") {
+ body, err := ioutil.ReadFile(req.URL.Path)
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.body = body
+ e.resp = &http.Response{
+ StatusCode: 200,
+ }
+ } else if e.resp == nil {
+ resp, err := httpDo(req)
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.resp = resp
+ // TODO: Spool to temp file.
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ resp.Body = nil
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.body = body
+ }
+ g.resp = e.resp
+ g.body = ioutil.NopCloser(bytes.NewReader(e.body))
+ e.mu.Unlock()
+
+ defer func() {
+ if g.body != nil {
+ g.body.Close()
+ }
+ }()
+
+ if !g.non200ok && g.resp.StatusCode != 200 {
+ return fmt.Errorf("unexpected status (%s): %v", url, g.resp.Status)
+ }
+
+ for _, o := range options {
+ if err := o.option(g); err != nil {
+ return err
+ }
+ }
+ return err
+}
diff --git a/vendor/cmd/go/internal/web2/web_test.go b/vendor/cmd/go/internal/web2/web_test.go
new file mode 100644
index 0000000..c6f6b1e
--- /dev/null
+++ b/vendor/cmd/go/internal/web2/web_test.go
@@ -0,0 +1,35 @@
+// Copyright 2018 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.
+
+package web2
+
+import (
+ "reflect"
+ "testing"
+)
+
+var testNetrc = `
+machine api.github.com
+ login user
+ password pwd
+
+machine incomlete.host
+ login justlogin
+
+machine test.host
+login user2
+password pwd2
+`
+
+func TestReadNetrc(t *testing.T) {
+ lines := parseNetrc(testNetrc)
+ want := []netrcLine{
+ {"api.github.com", "user", "pwd"},
+ {"test.host", "user2", "pwd2"},
+ }
+
+ if !reflect.DeepEqual(lines, want) {
+ t.Errorf("parseNetrc:\nhave %q\nwant %q", lines, want)
+ }
+}