blob: 5dc81de9b66110fcefe9c4448d41d3dfc691c921 [file] [log] [blame]
// Copyright 2017 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 web defines minimal helper routines for accessing HTTP/HTTPS
// resources without requiring external dependenicies on the net package.
//
// If the cmd_go_bootstrap build tag is present, web avoids the use of the net
// package and returns errors for all network operations.
package web
import (
"fmt"
"io"
"io/ioutil"
urlpkg "net/url"
)
// SecurityMode specifies whether a function should make network
// calls using insecure transports (eg, plain text HTTP).
// The zero value is "secure".
type SecurityMode int
const (
SecureOnly SecurityMode = iota // Reject plain HTTP; validate HTTPS.
DefaultSecurity // Allow plain HTTP if explicit; validate HTTPS.
Insecure // Allow plain HTTP if not explicitly HTTPS; skip HTTPS validation.
)
type HTTPError struct {
status string
StatusCode int
url *urlpkg.URL
}
func (e *HTTPError) Error() string {
return fmt.Sprintf("%s: %s", e.url, e.status)
}
// GetBytes returns the body of the requested resource, or an error if the
// response status was not http.StatusOk.
//
// GetBytes is a convenience wrapper around Get.
func GetBytes(url *urlpkg.URL) ([]byte, error) {
url, resp, err := Get(DefaultSecurity, 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
}
type Response struct {
Status string
StatusCode int
Header map[string][]string
Body io.ReadCloser
}
// Get returns the body of the HTTP or HTTPS resource specified at the given URL.
//
// If the URL does not include an explicit scheme, Get first tries "https".
// If the server does not respond under that scheme and the security mode is
// Insecure, Get then tries "http".
// The returned URL indicates which scheme was actually used.
//
// For the "https" scheme only, credentials are attached using the
// cmd/go/internal/auth package. If the URL itself includes a username and
// password, it will not be attempted under the "http" scheme unless the
// security mode is Insecure.
//
// Get returns a non-nil error only if the request did not receive a response
// under any applicable scheme. (A non-2xx response does not cause an error.)
func Get(security SecurityMode, url *urlpkg.URL) (*urlpkg.URL, *Response, error) {
return get(security, url)
}
// PasswordRedacted returns url directly if it does not encode a password,
// or else a copy of url with the password redacted.
func PasswordRedacted(url *urlpkg.URL) *urlpkg.URL {
if url.User != nil {
if _, ok := url.User.Password(); ok {
redacted := *url
redacted.User = urlpkg.UserPassword(url.User.Username(), "[redacted]")
return &redacted
}
}
return url
}
// OpenBrowser attempts to open the requested URL in a web browser.
func OpenBrowser(url string) (opened bool) {
return openBrowser(url)
}