github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/internal/devserver/pseudo.go (about) 1 // Copyright 2018 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package devserver 6 7 import ( 8 "context" 9 "fmt" 10 "io" 11 "net/http" 12 "net/url" 13 "os" 14 ) 15 16 const gsDownloadURL = "https://storage.googleapis.com" 17 18 // PseudoClient is an implementation of Client to simulate devservers without credentials. 19 type PseudoClient struct { 20 cl *http.Client 21 baseURL string 22 } 23 24 var _ Client = &PseudoClient{} 25 26 type pseudoClientOptions struct { 27 cl *http.Client 28 baseURL string 29 } 30 31 // PseudoClientOption is an option accepted by NewPseudoClient to configure 32 // PseudoClient initialization. 33 type PseudoClientOption func(o *pseudoClientOptions) 34 35 // WithHTTPClient returns an option that specifies http.Client used by 36 // PseudoClient. 37 func WithHTTPClient(cl *http.Client) PseudoClientOption { 38 return func(o *pseudoClientOptions) { o.cl = cl } 39 } 40 41 // WithBaseURL returns an option that specifies the base URL of Google Cloud 42 // Storage HTTP API. 43 func WithBaseURL(baseURL string) PseudoClientOption { 44 return func(o *pseudoClientOptions) { o.baseURL = baseURL } 45 } 46 47 // NewPseudoClient creates a PseudoClient. 48 func NewPseudoClient(opts ...PseudoClientOption) *PseudoClient { 49 o := &pseudoClientOptions{ 50 cl: defaultHTTPClient, 51 baseURL: gsDownloadURL, 52 } 53 for _, opts := range opts { 54 opts(o) 55 } 56 return &PseudoClient{cl: o.cl, baseURL: o.baseURL} 57 } 58 59 // TearDown does nothing. 60 func (c *PseudoClient) TearDown() error { 61 return nil 62 } 63 64 // Stage returns a url to GCS directly from storage.googleapis.com. 65 func (c *PseudoClient) Stage(ctx context.Context, gsURL string) (*url.URL, error) { 66 bucket, path, err := ParseGSURL(gsURL) 67 if err != nil { 68 return nil, err 69 } 70 71 dlURL, _ := url.Parse(c.baseURL) 72 dlURL.Path = fmt.Sprintf("/%s/%s", bucket, path) 73 return dlURL, nil 74 } 75 76 // Open downloads a file on GCS directly from storage.googleapis.com. 77 func (c *PseudoClient) Open(ctx context.Context, gsURL string) (io.ReadCloser, error) { 78 dlURL, err := c.Stage(ctx, gsURL) 79 if err != nil { 80 return nil, err 81 } 82 req, err := http.NewRequest("GET", dlURL.String(), nil) 83 if err != nil { 84 return nil, err 85 } 86 req = req.WithContext(ctx) 87 88 res, err := c.cl.Do(req) 89 if err != nil { 90 return nil, err 91 } 92 93 switch res.StatusCode { 94 case http.StatusOK: 95 return res.Body, nil 96 case http.StatusNotFound: 97 res.Body.Close() 98 return nil, os.ErrNotExist 99 default: 100 res.Body.Close() 101 return nil, fmt.Errorf("got status %d", res.StatusCode) 102 } 103 }