You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

webbrowser.go 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Package webbrowser provides a simple API for opening web pages on your
  2. // default browser.
  3. package webbrowser
  4. import (
  5. "errors"
  6. "fmt"
  7. "net/url"
  8. "os"
  9. "os/exec"
  10. "runtime"
  11. "strings"
  12. )
  13. var (
  14. ErrCantOpenBrowser = errors.New("webbrowser: can't open browser")
  15. ErrNoCandidates = errors.New("webbrowser: no browser candidate found for your OS")
  16. )
  17. // Candidates contains a list of registered `Browser`s that will be tried with Open.
  18. var Candidates []Browser
  19. type Browser interface {
  20. // Command returns a ready to be used Cmd that will open an URL.
  21. Command(string) (*exec.Cmd, error)
  22. // Open tries to open a URL in your default browser. NOTE: This may cause
  23. // your program to hang until the browser process is closed in some OSes,
  24. // see https://github.com/toqueteos/webbrowser/issues/4.
  25. Open(string) error
  26. }
  27. // Open tries to open a URL in your default browser ensuring you have a display
  28. // set up and not running this from SSH. NOTE: This may cause your program to
  29. // hang until the browser process is closed in some OSes, see
  30. // https://github.com/toqueteos/webbrowser/issues/4.
  31. func Open(s string) (err error) {
  32. if len(Candidates) == 0 {
  33. return ErrNoCandidates
  34. }
  35. // Try to determine if there's a display available (only linux) and we
  36. // aren't on a terminal (all but windows).
  37. switch runtime.GOOS {
  38. case "linux":
  39. // No display, no need to open a browser. Lynx users **MAY** have
  40. // something to say about this.
  41. if os.Getenv("DISPLAY") == "" {
  42. return fmt.Errorf("webbrowser: tried to open %q, no screen found", s)
  43. }
  44. fallthrough
  45. case "darwin":
  46. // Check SSH env vars.
  47. if os.Getenv("SSH_CLIENT") != "" || os.Getenv("SSH_TTY") != "" {
  48. return fmt.Errorf("webbrowser: tried to open %q, but you are running a shell session", s)
  49. }
  50. }
  51. // Try all candidates
  52. for _, candidate := range Candidates {
  53. err := candidate.Open(s)
  54. if err == nil {
  55. return nil
  56. }
  57. }
  58. return ErrCantOpenBrowser
  59. }
  60. func init() {
  61. // Register the default Browser for current OS, if it exists.
  62. if os, ok := osCommand[runtime.GOOS]; ok {
  63. Candidates = append(Candidates, browserCommand{os.cmd, os.args})
  64. }
  65. }
  66. var (
  67. osCommand = map[string]*browserCommand{
  68. "android": &browserCommand{"xdg-open", nil},
  69. "darwin": &browserCommand{"open", nil},
  70. "freebsd": &browserCommand{"xdg-open", nil},
  71. "linux": &browserCommand{"xdg-open", nil},
  72. "netbsd": &browserCommand{"xdg-open", nil},
  73. "openbsd": &browserCommand{"xdg-open", nil}, // It may be open instead
  74. "windows": &browserCommand{"cmd", []string{"/c", "start"}},
  75. }
  76. winSchemes = [3]string{"https", "http", "file"}
  77. )
  78. type browserCommand struct {
  79. cmd string
  80. args []string
  81. }
  82. func (b browserCommand) Command(s string) (*exec.Cmd, error) {
  83. u, err := url.Parse(s)
  84. if err != nil {
  85. return nil, err
  86. }
  87. validUrl := ensureValidURL(u)
  88. b.args = append(b.args, validUrl)
  89. return exec.Command(b.cmd, b.args...), nil
  90. }
  91. func (b browserCommand) Open(s string) error {
  92. cmd, err := b.Command(s)
  93. if err != nil {
  94. return err
  95. }
  96. return cmd.Run()
  97. }
  98. func ensureScheme(u *url.URL) {
  99. for _, s := range winSchemes {
  100. if u.Scheme == s {
  101. return
  102. }
  103. }
  104. u.Scheme = "http"
  105. }
  106. func ensureValidURL(u *url.URL) string {
  107. // Enforce a scheme (windows requires scheme to be set to work properly).
  108. ensureScheme(u)
  109. s := u.String()
  110. // Escape characters not allowed by cmd/bash
  111. switch runtime.GOOS {
  112. case "windows":
  113. s = strings.Replace(s, "&", `^&`, -1)
  114. }
  115. return s
  116. }