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  }