Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| // Package webbrowser provides a simple API for opening web pages on your | |
| // default browser. | |
| package webbrowser | |
| import ( | |
| "errors" | |
| "fmt" | |
| "net/url" | |
| "os" | |
| "os/exec" | |
| "runtime" | |
| "strings" | |
| ) | |
| var ( | |
| ErrCantOpenBrowser = errors.New("webbrowser: can't open browser") | |
| ErrNoCandidates = errors.New("webbrowser: no browser candidate found for your OS") | |
| ) | |
| // Candidates contains a list of registered `Browser`s that will be tried with Open. | |
| var Candidates []Browser | |
| type Browser interface { | |
| // Command returns a ready to be used Cmd that will open an URL. | |
| Command(string) (*exec.Cmd, error) | |
| // Open tries to open a URL in your default browser. NOTE: This may cause | |
| // your program to hang until the browser process is closed in some OSes, | |
| // see https://github.com/toqueteos/webbrowser/issues/4. | |
| Open(string) error | |
| } | |
| // Open tries to open a URL in your default browser ensuring you have a display | |
| // set up and not running this from SSH. NOTE: This may cause your program to | |
| // hang until the browser process is closed in some OSes, see | |
| // https://github.com/toqueteos/webbrowser/issues/4. | |
| func Open(s string) (err error) { | |
| if len(Candidates) == 0 { | |
| return ErrNoCandidates | |
| } | |
| // Try to determine if there's a display available (only linux) and we | |
| // aren't on a terminal (all but windows). | |
| switch runtime.GOOS { | |
| case "linux": | |
| // No display, no need to open a browser. Lynx users **MAY** have | |
| // something to say about this. | |
| if os.Getenv("DISPLAY") == "" { | |
| return fmt.Errorf("webbrowser: tried to open %q, no screen found", s) | |
| } | |
| fallthrough | |
| case "darwin": | |
| // Check SSH env vars. | |
| if os.Getenv("SSH_CLIENT") != "" || os.Getenv("SSH_TTY") != "" { | |
| return fmt.Errorf("webbrowser: tried to open %q, but you are running a shell session", s) | |
| } | |
| } | |
| // Try all candidates | |
| for _, candidate := range Candidates { | |
| err := candidate.Open(s) | |
| if err == nil { | |
| return nil | |
| } | |
| } | |
| return ErrCantOpenBrowser | |
| } | |
| func init() { | |
| // Register the default Browser for current OS, if it exists. | |
| if os, ok := osCommand[runtime.GOOS]; ok { | |
| Candidates = append(Candidates, browserCommand{os.cmd, os.args}) | |
| } | |
| } | |
| var ( | |
| osCommand = map[string]*browserCommand{ | |
| "android": &browserCommand{"xdg-open", nil}, | |
| "darwin": &browserCommand{"open", nil}, | |
| "freebsd": &browserCommand{"xdg-open", nil}, | |
| "linux": &browserCommand{"xdg-open", nil}, | |
| "netbsd": &browserCommand{"xdg-open", nil}, | |
| "openbsd": &browserCommand{"xdg-open", nil}, // It may be open instead | |
| "windows": &browserCommand{"cmd", []string{"/c", "start"}}, | |
| } | |
| winSchemes = [3]string{"https", "http", "file"} | |
| ) | |
| type browserCommand struct { | |
| cmd string | |
| args []string | |
| } | |
| func (b browserCommand) Command(s string) (*exec.Cmd, error) { | |
| u, err := url.Parse(s) | |
| if err != nil { | |
| return nil, err | |
| } | |
| validUrl := ensureValidURL(u) | |
| b.args = append(b.args, validUrl) | |
| return exec.Command(b.cmd, b.args...), nil | |
| } | |
| func (b browserCommand) Open(s string) error { | |
| cmd, err := b.Command(s) | |
| if err != nil { | |
| return err | |
| } | |
| return cmd.Run() | |
| } | |
| func ensureScheme(u *url.URL) { | |
| for _, s := range winSchemes { | |
| if u.Scheme == s { | |
| return | |
| } | |
| } | |
| u.Scheme = "http" | |
| } | |
| func ensureValidURL(u *url.URL) string { | |
| // Enforce a scheme (windows requires scheme to be set to work properly). | |
| ensureScheme(u) | |
| s := u.String() | |
| // Escape characters not allowed by cmd/bash | |
| switch runtime.GOOS { | |
| case "windows": | |
| s = strings.Replace(s, "&", `^&`, -1) | |
| } | |
| return s | |
| } |