github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/resources_unit.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/names/v5"
    13  
    14  	"github.com/juju/juju/core/resources"
    15  	"github.com/juju/juju/rpc/params"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  // UnitResourcesHandler is the HTTP handler for unit agent downloads of
    20  // resources.
    21  type UnitResourcesHandler struct {
    22  	NewOpener func(*http.Request, ...string) (resources.Opener, state.PoolHelper, error)
    23  }
    24  
    25  // ServeHTTP implements http.Handler.
    26  func (h *UnitResourcesHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
    27  	switch req.Method {
    28  	case "GET":
    29  		opener, ph, err := h.NewOpener(req, names.UnitTagKind, names.ApplicationTagKind)
    30  		if err != nil {
    31  			if err := sendError(resp, err); err != nil {
    32  				logger.Errorf("%v", err)
    33  			}
    34  			return
    35  		}
    36  		defer ph.Release()
    37  
    38  		name := req.URL.Query().Get(":resource")
    39  		opened, err := opener.OpenResource(name)
    40  		if err != nil {
    41  			if errors.IsNotFound(err) {
    42  				// non internal errors is not real errors.
    43  				logger.Warningf("cannot fetch resource reader: %v", err)
    44  			} else {
    45  				logger.Errorf("cannot fetch resource reader: %v", err)
    46  			}
    47  			if err := sendError(resp, err); err != nil {
    48  				logger.Errorf("%v", err)
    49  			}
    50  			return
    51  		}
    52  		defer opened.Close()
    53  
    54  		hdr := resp.Header()
    55  		hdr.Set("Content-Type", params.ContentTypeRaw)
    56  		hdr.Set("Content-Length", fmt.Sprint(opened.Size))
    57  		hdr.Set("Content-Sha384", opened.Fingerprint.String())
    58  
    59  		resp.WriteHeader(http.StatusOK)
    60  		if _, err := io.Copy(resp, opened); err != nil {
    61  			// We cannot use SendHTTPError here, so we log the error
    62  			// and move on.
    63  			logger.Errorf("unable to complete stream for resource: %v", err)
    64  			return
    65  		}
    66  	default:
    67  		if err := sendError(resp, errors.MethodNotAllowedf("unsupported method: %q", req.Method)); err != nil {
    68  			logger.Errorf("%v", err)
    69  		}
    70  	}
    71  }