123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- package main
- import (
- "context"
- "errors"
- "io"
- "net"
- "net/http"
- "net/url"
- "os"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing-box/log"
- "github.com/sagernet/sing/common/bufio"
- E "github.com/sagernet/sing/common/exceptions"
- M "github.com/sagernet/sing/common/metadata"
- "github.com/spf13/cobra"
- )
- var commandFetch = &cobra.Command{
- Use: "fetch",
- Short: "Fetch an URL",
- Args: cobra.MinimumNArgs(1),
- Run: func(cmd *cobra.Command, args []string) {
- err := fetch(args)
- if err != nil {
- log.Fatal(err)
- }
- },
- }
- func init() {
- commandTools.AddCommand(commandFetch)
- }
- var (
- httpClient *http.Client
- http3Client *http.Client
- )
- func fetch(args []string) error {
- instance, err := createPreStartedClient()
- if err != nil {
- return err
- }
- defer instance.Close()
- httpClient = &http.Client{
- Transport: &http.Transport{
- DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
- dialer, err := createDialer(instance, commandToolsFlagOutbound)
- if err != nil {
- return nil, err
- }
- return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
- },
- ForceAttemptHTTP2: true,
- },
- }
- defer httpClient.CloseIdleConnections()
- if C.WithQUIC {
- err = initializeHTTP3Client(instance)
- if err != nil {
- return err
- }
- defer http3Client.CloseIdleConnections()
- }
- for _, urlString := range args {
- var parsedURL *url.URL
- parsedURL, err = url.Parse(urlString)
- if err != nil {
- return err
- }
- switch parsedURL.Scheme {
- case "":
- parsedURL.Scheme = "http"
- fallthrough
- case "http", "https":
- err = fetchHTTP(httpClient, parsedURL)
- if err != nil {
- return err
- }
- case "http3":
- if !C.WithQUIC {
- return C.ErrQUICNotIncluded
- }
- parsedURL.Scheme = "https"
- err = fetchHTTP(http3Client, parsedURL)
- if err != nil {
- return err
- }
- default:
- return E.New("unsupported scheme: ", parsedURL.Scheme)
- }
- }
- return nil
- }
- func fetchHTTP(httpClient *http.Client, parsedURL *url.URL) error {
- request, err := http.NewRequest("GET", parsedURL.String(), nil)
- if err != nil {
- return err
- }
- request.Header.Add("User-Agent", "curl/7.88.0")
- response, err := httpClient.Do(request)
- if err != nil {
- return err
- }
- defer response.Body.Close()
- _, err = bufio.Copy(os.Stdout, response.Body)
- if errors.Is(err, io.EOF) {
- return nil
- }
- return err
- }
|