sing-box/cmd/sing-box/cmd_tools_fetch.go

116 lines
2.3 KiB
Go
Raw Normal View History

2023-03-18 13:02:29 +00:00
package main
import (
"context"
"errors"
"io"
"net"
"net/http"
"net/url"
"os"
2024-06-07 07:55:21 +00:00
C "github.com/sagernet/sing-box/constant"
2023-03-18 13:02:29 +00:00
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common/bufio"
2024-06-07 07:55:21 +00:00
E "github.com/sagernet/sing/common/exceptions"
2023-03-18 13:02:29 +00:00
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)
}
2024-06-07 07:55:21 +00:00
var (
httpClient *http.Client
http3Client *http.Client
)
2023-03-18 13:02:29 +00:00
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)
2023-03-18 13:02:29 +00:00
if err != nil {
return nil, err
}
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
},
ForceAttemptHTTP2: true,
},
}
defer httpClient.CloseIdleConnections()
2024-06-07 07:55:21 +00:00
if C.WithQUIC {
err = initializeHTTP3Client(instance)
if err != nil {
return err
}
defer http3Client.CloseIdleConnections()
}
2023-03-18 13:02:29 +00:00
for _, urlString := range args {
2024-06-07 07:55:21 +00:00
var parsedURL *url.URL
parsedURL, err = url.Parse(urlString)
2023-03-18 13:02:29 +00:00
if err != nil {
return err
}
switch parsedURL.Scheme {
case "":
parsedURL.Scheme = "http"
fallthrough
case "http", "https":
2024-06-07 07:55:21 +00:00
err = fetchHTTP(httpClient, parsedURL)
if err != nil {
return err
}
case "http3":
if !C.WithQUIC {
return C.ErrQUICNotIncluded
}
parsedURL.Scheme = "https"
err = fetchHTTP(http3Client, parsedURL)
2023-03-18 13:02:29 +00:00
if err != nil {
return err
}
2024-06-07 07:55:21 +00:00
default:
return E.New("unsupported scheme: ", parsedURL.Scheme)
2023-03-18 13:02:29 +00:00
}
}
return nil
}
2024-06-07 07:55:21 +00:00
func fetchHTTP(httpClient *http.Client, parsedURL *url.URL) error {
2023-03-18 13:02:29 +00:00
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
}