github.com/uber/kraken@v0.1.4/lib/backend/httpbackend/http.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package httpbackend
    15  
    16  import (
    17  	"bytes"
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"time"
    22  
    23  	"github.com/uber/kraken/core"
    24  	"github.com/uber/kraken/lib/backend"
    25  	"github.com/uber/kraken/lib/backend/backenderrors"
    26  	"github.com/uber/kraken/utils/httputil"
    27  
    28  	"gopkg.in/yaml.v2"
    29  )
    30  
    31  const _http = "http"
    32  
    33  func init() {
    34  	backend.Register(_http, &factory{})
    35  }
    36  
    37  type factory struct{}
    38  
    39  func (f *factory) Create(
    40  	confRaw interface{}, authConfRaw interface{}) (backend.Client, error) {
    41  
    42  	confBytes, err := yaml.Marshal(confRaw)
    43  	if err != nil {
    44  		return nil, errors.New("marshal http config")
    45  	}
    46  
    47  	var config Config
    48  	if err := yaml.Unmarshal(confBytes, &config); err != nil {
    49  		return nil, errors.New("unmarshal http config")
    50  	}
    51  	return NewClient(config)
    52  }
    53  
    54  // Config defines http post/get upload/download urls
    55  // and http connnection parameters. The URLs come with string format
    56  // specifiers and define how to pass sha256 parameters
    57  type Config struct {
    58  	UploadURL       string                            `yaml:"upload_url"`   // http upload post url
    59  	DownloadURL     string                            `yaml:"download_url"` // http download get url
    60  	DownloadTimeout time.Duration                     `yaml:"download_timeout"`
    61  	DownloadBackOff httputil.ExponentialBackOffConfig `yaml:"download_backoff"`
    62  }
    63  
    64  // Client implements downloading/uploading object from/to S3
    65  type Client struct {
    66  	config Config
    67  }
    68  
    69  func (c Config) applyDefaults() Config {
    70  	if c.DownloadTimeout == 0 {
    71  		c.DownloadTimeout = 180 * time.Second
    72  	}
    73  	return c
    74  }
    75  
    76  // NewClient creates a new http Client.
    77  func NewClient(config Config) (*Client, error) {
    78  	return &Client{config: config.applyDefaults()}, nil
    79  }
    80  
    81  // Stat always succeeds.
    82  // TODO(codyg): Support stat URL.
    83  func (c *Client) Stat(namespace, name string) (*core.BlobInfo, error) {
    84  	return core.NewBlobInfo(0), nil
    85  }
    86  
    87  // Download downloads the content from a configured url and writes the data
    88  // to dst.
    89  func (c *Client) Download(namespace, name string, dst io.Writer) error {
    90  	// Use Fprintf instead of Sprintf to handle formatting errors.
    91  	var b bytes.Buffer
    92  	if _, err := fmt.Fprintf(&b, c.config.DownloadURL, name); err != nil {
    93  		return fmt.Errorf("format url: %s", err)
    94  	}
    95  	resp, err := httputil.Get(
    96  		b.String(),
    97  		httputil.SendTimeout(c.config.DownloadTimeout),
    98  		httputil.SendRetry(httputil.RetryBackoff(c.config.DownloadBackOff.Build())))
    99  	if err != nil {
   100  		if httputil.IsNotFound(err) {
   101  			return backenderrors.ErrBlobNotFound
   102  		}
   103  		return err
   104  	}
   105  	defer resp.Body.Close()
   106  	if _, err := io.Copy(dst, resp.Body); err != nil {
   107  		return fmt.Errorf("copy: %s", err)
   108  	}
   109  	return nil
   110  }
   111  
   112  // Upload is not supported.
   113  func (c *Client) Upload(namespace, name string, src io.Reader) error {
   114  	return errors.New("not supported")
   115  }
   116  
   117  // List is not supported.
   118  func (c *Client) List(prefix string, opts ...backend.ListOption) (*backend.ListResult, error) {
   119  	return nil, errors.New("not supported")
   120  }