github.com/richardwilkes/toolbox@v1.121.0/xio/retrieve.go (about)

     1  // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, version 2.0. If a copy of the MPL was not distributed with
     5  // this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  //
     7  // This Source Code Form is "Incompatible With Secondary Licenses", as
     8  // defined by the Mozilla Public License, version 2.0.
     9  
    10  package xio
    11  
    12  import (
    13  	"context"
    14  	"io"
    15  	"net/http"
    16  	"net/url"
    17  	"os"
    18  	"strings"
    19  
    20  	"github.com/richardwilkes/toolbox/errs"
    21  )
    22  
    23  // RetrieveData loads the bytes from the given file path or URL of type file, http, or https.
    24  func RetrieveData(filePathOrURL string) ([]byte, error) {
    25  	return RetrieveDataWithContext(context.Background(), filePathOrURL)
    26  }
    27  
    28  // RetrieveDataWithContext loads the bytes from the given file path or URL of type file, http, or https.
    29  func RetrieveDataWithContext(ctx context.Context, filePathOrURL string) ([]byte, error) {
    30  	if strings.HasPrefix(filePathOrURL, "http://") ||
    31  		strings.HasPrefix(filePathOrURL, "https://") ||
    32  		strings.HasPrefix(filePathOrURL, "file://") {
    33  		return RetrieveDataFromURLWithContext(ctx, filePathOrURL)
    34  	}
    35  	data, err := os.ReadFile(filePathOrURL)
    36  	if err != nil {
    37  		return nil, errs.NewWithCause(filePathOrURL, err)
    38  	}
    39  	return data, nil
    40  }
    41  
    42  // RetrieveDataFromURL loads the bytes from the given URL of type file, http, or https.
    43  func RetrieveDataFromURL(urlStr string) ([]byte, error) {
    44  	return RetrieveDataFromURLWithContext(context.Background(), urlStr)
    45  }
    46  
    47  // RetrieveDataFromURLWithContext loads the bytes from the given URL of type file, http, or https.
    48  func RetrieveDataFromURLWithContext(ctx context.Context, urlStr string) ([]byte, error) {
    49  	u, err := url.Parse(urlStr)
    50  	if err != nil {
    51  		return nil, errs.NewWithCause(urlStr, err)
    52  	}
    53  	var data []byte
    54  	switch u.Scheme {
    55  	case "file":
    56  		if data, err = os.ReadFile(u.Path); err != nil {
    57  			return nil, errs.NewWithCause(urlStr, err)
    58  		}
    59  		return data, nil
    60  	case "http", "https":
    61  		var req *http.Request
    62  		req, err = http.NewRequestWithContext(ctx, http.MethodGet, urlStr, http.NoBody)
    63  		if err != nil {
    64  			return nil, errs.NewWithCause("unable to create request", err)
    65  		}
    66  		var rsp *http.Response
    67  		if rsp, err = http.DefaultClient.Do(req); err != nil {
    68  			return nil, errs.NewWithCause(urlStr, err)
    69  		}
    70  		defer DiscardAndCloseIgnoringErrors(rsp.Body)
    71  		if rsp.StatusCode < 200 || rsp.StatusCode > 299 {
    72  			return nil, errs.NewWithCause(urlStr, errs.Newf("received status %d (%s)", rsp.StatusCode, rsp.Status))
    73  		}
    74  		data, err = io.ReadAll(rsp.Body)
    75  		if err != nil {
    76  			return nil, errs.NewWithCause(urlStr, err)
    77  		}
    78  		return data, nil
    79  	default:
    80  		return nil, errs.Newf("invalid url: %s", urlStr)
    81  	}
    82  }