external.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package external
  2. import (
  3. "bytes"
  4. "io"
  5. "net/http"
  6. "net/url"
  7. "os"
  8. "strings"
  9. "time"
  10. "github.com/xtls/xray-core/common/buf"
  11. "github.com/xtls/xray-core/common/errors"
  12. "github.com/xtls/xray-core/common/platform/ctlcmd"
  13. "github.com/xtls/xray-core/main/confloader"
  14. )
  15. func ConfigLoader(arg string) (out io.Reader, err error) {
  16. var data []byte
  17. switch {
  18. case strings.HasPrefix(arg, "http://"), strings.HasPrefix(arg, "https://"):
  19. data, err = FetchHTTPContent(arg)
  20. case arg == "stdin:":
  21. data, err = io.ReadAll(os.Stdin)
  22. default:
  23. data, err = os.ReadFile(arg)
  24. }
  25. if err != nil {
  26. return
  27. }
  28. out = bytes.NewBuffer(data)
  29. return
  30. }
  31. func FetchHTTPContent(target string) ([]byte, error) {
  32. parsedTarget, err := url.Parse(target)
  33. if err != nil {
  34. return nil, errors.New("invalid URL: ", target).Base(err)
  35. }
  36. if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" {
  37. return nil, errors.New("invalid scheme: ", parsedTarget.Scheme)
  38. }
  39. client := &http.Client{
  40. Timeout: 30 * time.Second,
  41. }
  42. resp, err := client.Do(&http.Request{
  43. Method: "GET",
  44. URL: parsedTarget,
  45. Close: true,
  46. })
  47. if err != nil {
  48. return nil, errors.New("failed to dial to ", target).Base(err)
  49. }
  50. defer resp.Body.Close()
  51. if resp.StatusCode != 200 {
  52. return nil, errors.New("unexpected HTTP status code: ", resp.StatusCode)
  53. }
  54. content, err := buf.ReadAllToBytes(resp.Body)
  55. if err != nil {
  56. return nil, errors.New("failed to read HTTP response").Base(err)
  57. }
  58. return content, nil
  59. }
  60. func ExtConfigLoader(files []string, reader io.Reader) (io.Reader, error) {
  61. buf, err := ctlcmd.Run(append([]string{"convert"}, files...), reader)
  62. if err != nil {
  63. return nil, err
  64. }
  65. return strings.NewReader(buf.String()), nil
  66. }
  67. func init() {
  68. confloader.EffectiveConfigFileLoader = ConfigLoader
  69. confloader.EffectiveExtConfigLoader = ExtConfigLoader
  70. }