github.com/v2fly/v2ray-core/v4@v4.45.2/infra/control/fetch.go (about) 1 package control 2 3 import ( 4 "net/http" 5 "net/url" 6 "os" 7 "strings" 8 "time" 9 10 "github.com/v2fly/v2ray-core/v4/common" 11 "github.com/v2fly/v2ray-core/v4/common/buf" 12 ) 13 14 type FetchCommand struct{} 15 16 func (c *FetchCommand) Name() string { 17 return "fetch" 18 } 19 20 func (c *FetchCommand) Description() Description { 21 return Description{ 22 Short: "Fetch resources", 23 Usage: []string{"v2ctl fetch <url>"}, 24 } 25 } 26 27 func (c *FetchCommand) Execute(args []string) error { 28 if len(args) < 1 { 29 return newError("empty url") 30 } 31 content, err := FetchHTTPContent(args[0]) 32 if err != nil { 33 return newError("failed to read HTTP response").Base(err) 34 } 35 36 os.Stdout.Write(content) 37 return nil 38 } 39 40 // FetchHTTPContent dials https for remote content 41 func FetchHTTPContent(target string) ([]byte, error) { 42 parsedTarget, err := url.Parse(target) 43 if err != nil { 44 return nil, newError("invalid URL: ", target).Base(err) 45 } 46 47 if s := strings.ToLower(parsedTarget.Scheme); s != "http" && s != "https" { 48 return nil, newError("invalid scheme: ", parsedTarget.Scheme) 49 } 50 51 client := &http.Client{ 52 Timeout: 30 * time.Second, 53 } 54 resp, err := client.Do(&http.Request{ 55 Method: "GET", 56 URL: parsedTarget, 57 Close: true, 58 }) 59 if err != nil { 60 return nil, newError("failed to dial to ", target).Base(err) 61 } 62 defer resp.Body.Close() 63 64 if resp.StatusCode != 200 { 65 return nil, newError("unexpected HTTP status code: ", resp.StatusCode) 66 } 67 68 content, err := buf.ReadAllToBytes(resp.Body) 69 if err != nil { 70 return nil, newError("failed to read HTTP response").Base(err) 71 } 72 73 return content, nil 74 } 75 76 func init() { 77 common.Must(RegisterCommand(&FetchCommand{})) 78 }