github.com/sagernet/sing-box@v1.9.0-rc.20/cmd/sing-box/cmd_tools_fetch.go (about) 1 package main 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "net" 8 "net/http" 9 "net/url" 10 "os" 11 12 "github.com/sagernet/sing-box/log" 13 "github.com/sagernet/sing/common/bufio" 14 M "github.com/sagernet/sing/common/metadata" 15 16 "github.com/spf13/cobra" 17 ) 18 19 var commandFetch = &cobra.Command{ 20 Use: "fetch", 21 Short: "Fetch an URL", 22 Args: cobra.MinimumNArgs(1), 23 Run: func(cmd *cobra.Command, args []string) { 24 err := fetch(args) 25 if err != nil { 26 log.Fatal(err) 27 } 28 }, 29 } 30 31 func init() { 32 commandTools.AddCommand(commandFetch) 33 } 34 35 var httpClient *http.Client 36 37 func fetch(args []string) error { 38 instance, err := createPreStartedClient() 39 if err != nil { 40 return err 41 } 42 defer instance.Close() 43 httpClient = &http.Client{ 44 Transport: &http.Transport{ 45 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { 46 dialer, err := createDialer(instance, network, commandToolsFlagOutbound) 47 if err != nil { 48 return nil, err 49 } 50 return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) 51 }, 52 ForceAttemptHTTP2: true, 53 }, 54 } 55 defer httpClient.CloseIdleConnections() 56 for _, urlString := range args { 57 parsedURL, err := url.Parse(urlString) 58 if err != nil { 59 return err 60 } 61 switch parsedURL.Scheme { 62 case "": 63 parsedURL.Scheme = "http" 64 fallthrough 65 case "http", "https": 66 err = fetchHTTP(parsedURL) 67 if err != nil { 68 return err 69 } 70 } 71 } 72 return nil 73 } 74 75 func fetchHTTP(parsedURL *url.URL) error { 76 request, err := http.NewRequest("GET", parsedURL.String(), nil) 77 if err != nil { 78 return err 79 } 80 request.Header.Add("User-Agent", "curl/7.88.0") 81 response, err := httpClient.Do(request) 82 if err != nil { 83 return err 84 } 85 defer response.Body.Close() 86 _, err = bufio.Copy(os.Stdout, response.Body) 87 if errors.Is(err, io.EOF) { 88 return nil 89 } 90 return err 91 }