gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
  101. 101
  102. 102
  103. 103
  104. 104
  105. 105
  106. 106
  107. 107
  108. 108
  109. 109
  110. 110
  111. 111
  112. 112
  113. 113
  114. 114
  115. 115
  116. 116
  117. 117
  118. 118
  119. 119
  120. 120
  121. 121
  122. 122
  123. 123
  124. 124
  125. 125
  126. 126
  127. 127
  128. 128
  129. 129
  130. 130
  131. 131
  132. 132
  133. 133
  134. 134
  135. 135
  136. 136
  137. 137
// 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
}