diff options
Diffstat (limited to 'libgo/go/cmd/go/internal/web/http.go')
-rw-r--r-- | libgo/go/cmd/go/internal/web/http.go | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/libgo/go/cmd/go/internal/web/http.go b/libgo/go/cmd/go/internal/web/http.go new file mode 100644 index 00000000000..6e347fbf860 --- /dev/null +++ b/libgo/go/cmd/go/internal/web/http.go @@ -0,0 +1,122 @@ +// Copyright 2012 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. + +// +build !cmd_go_bootstrap + +// This code is compiled into the real 'go' binary, but it is not +// compiled into the binary that is built during all.bash, so as +// to avoid needing to build net (and thus use cgo) during the +// bootstrap process. + +package web + +import ( + "crypto/tls" + "fmt" + "io" + "io/ioutil" + "log" + "net/http" + "net/url" + "time" + + "cmd/go/internal/cfg" + "cmd/internal/browser" +) + +// httpClient is the default HTTP client, but a variable so it can be +// changed by tests, without modifying http.DefaultClient. +var httpClient = http.DefaultClient + +// impatientInsecureHTTPClient is used in -insecure mode, +// when we're connecting to https servers that might not be there +// or might be using self-signed certificates. +var impatientInsecureHTTPClient = &http.Client{ + Timeout: 5 * time.Second, + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, +} + +type HTTPError struct { + status string + StatusCode int + url string +} + +func (e *HTTPError) Error() string { + return fmt.Sprintf("%s: %s", e.url, e.status) +} + +// Get returns the data from an HTTP GET request for the given URL. +func Get(url string) ([]byte, error) { + resp, err := httpClient.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + err := &HTTPError{status: resp.Status, StatusCode: resp.StatusCode, url: url} + + return nil, err + } + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("%s: %v", url, err) + } + return b, nil +} + +// GetMaybeInsecure returns the body of either the importPath's +// https resource or, if unavailable and permitted by the security mode, the http resource. +func GetMaybeInsecure(importPath string, security SecurityMode) (urlStr string, body io.ReadCloser, err error) { + fetch := func(scheme string) (urlStr string, res *http.Response, err error) { + u, err := url.Parse(scheme + "://" + importPath) + if err != nil { + return "", nil, err + } + u.RawQuery = "go-get=1" + urlStr = u.String() + if cfg.BuildV { + log.Printf("Fetching %s", urlStr) + } + if security == Insecure && scheme == "https" { // fail earlier + res, err = impatientInsecureHTTPClient.Get(urlStr) + } else { + res, err = httpClient.Get(urlStr) + } + return + } + closeBody := func(res *http.Response) { + if res != nil { + res.Body.Close() + } + } + urlStr, res, err := fetch("https") + if err != nil { + if cfg.BuildV { + log.Printf("https fetch failed: %v", err) + } + if security == Insecure { + closeBody(res) + urlStr, res, err = fetch("http") + } + } + if err != nil { + closeBody(res) + return "", nil, err + } + // Note: accepting a non-200 OK here, so people can serve a + // meta import in their http 404 page. + if cfg.BuildV { + log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode) + } + return urlStr, res.Body, nil +} + +func QueryEscape(s string) string { return url.QueryEscape(s) } +func OpenBrowser(url string) bool { return browser.Open(url) } |