github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/go/http.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !cmd_go_bootstrap 6 7 // This code is compiled into the real 'go' binary, but it is not 8 // compiled into the binary that is built during all.bash, so as 9 // to avoid needing to build net (and thus use cgo) during the 10 // bootstrap process. 11 12 package main 13 14 import ( 15 "fmt" 16 "io" 17 "io/ioutil" 18 "log" 19 "net/http" 20 "net/url" 21 "time" 22 ) 23 24 // httpClient is the default HTTP client, but a variable so it can be 25 // changed by tests, without modifying http.DefaultClient. 26 var httpClient = http.DefaultClient 27 var impatientHTTPClient = &http.Client{ 28 Timeout: time.Duration(5 * time.Second), 29 } 30 31 type httpError struct { 32 status string 33 statusCode int 34 url string 35 } 36 37 func (e *httpError) Error() string { 38 return fmt.Sprintf("%s: %s", e.url, e.status) 39 } 40 41 // httpGET returns the data from an HTTP GET request for the given URL. 42 func httpGET(url string) ([]byte, error) { 43 resp, err := httpClient.Get(url) 44 if err != nil { 45 return nil, err 46 } 47 defer resp.Body.Close() 48 if resp.StatusCode != 200 { 49 err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url} 50 51 return nil, err 52 } 53 b, err := ioutil.ReadAll(resp.Body) 54 if err != nil { 55 return nil, fmt.Errorf("%s: %v", url, err) 56 } 57 return b, nil 58 } 59 60 // httpsOrHTTP returns the body of either the importPath's 61 // https resource or, if unavailable, the http resource. 62 func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body io.ReadCloser, err error) { 63 fetch := func(scheme string) (urlStr string, res *http.Response, err error) { 64 u, err := url.Parse(scheme + "://" + importPath) 65 if err != nil { 66 return "", nil, err 67 } 68 u.RawQuery = "go-get=1" 69 urlStr = u.String() 70 if buildV { 71 log.Printf("Fetching %s", urlStr) 72 } 73 if security == insecure && scheme == "https" { // fail earlier 74 res, err = impatientHTTPClient.Get(urlStr) 75 } else { 76 res, err = httpClient.Get(urlStr) 77 } 78 return 79 } 80 closeBody := func(res *http.Response) { 81 if res != nil { 82 res.Body.Close() 83 } 84 } 85 urlStr, res, err := fetch("https") 86 if err != nil || res.StatusCode != 200 { 87 if buildV { 88 if err != nil { 89 log.Printf("https fetch failed.") 90 } else { 91 log.Printf("ignoring https fetch with status code %d", res.StatusCode) 92 } 93 } 94 closeBody(res) 95 if security == insecure { 96 urlStr, res, err = fetch("http") 97 } 98 } 99 if err != nil { 100 closeBody(res) 101 return "", nil, err 102 } 103 // Note: accepting a non-200 OK here, so people can serve a 104 // meta import in their http 404 page. 105 if buildV { 106 log.Printf("Parsing meta tags from %s (status code %d)", urlStr, res.StatusCode) 107 } 108 return urlStr, res.Body, nil 109 }