storage/resolver.go (70 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.
package storage
import (
"fmt"
"io"
"net/http"
"net/url"
"github.com/elastic/package-registry/packages"
)
type storageResolver struct {
client *http.Client
artifactsPackagesURL url.URL
artifactsStaticURL url.URL
}
var acceptedHeaders = map[string]string{
"Content-Length": "",
"Content-Type": "",
"Last-Modified": "",
"Date": "",
}
func (resolver storageResolver) pipeRequestProxy(w http.ResponseWriter, r *http.Request, remoteURL string) {
forwardRequest, err := http.NewRequestWithContext(r.Context(), r.Method, remoteURL, nil)
if err != nil {
http.Error(w, "failed to create request for the package-storage", http.StatusInternalServerError)
return
}
resp, err := resolver.client.Do(forwardRequest)
if err != nil {
http.Error(w, "error from package-storage server", http.StatusInternalServerError)
return
}
defer resp.Body.Close()
// Set headers before setting the body. If not, first call to w.Write will
// add some default values.
addRequestHeadersToResponse(w, resp)
w.WriteHeader(resp.StatusCode)
_, err = io.Copy(w, resp.Body)
if err != nil {
http.Error(w, "error writing response", http.StatusInternalServerError)
return
}
}
func addRequestHeadersToResponse(w http.ResponseWriter, resp *http.Response) {
for header, values := range resp.Header {
if len(w.Header().Values(header)) > 0 {
// do not overwrite
continue
}
if _, ok := acceptedHeaders[header]; !ok {
continue
}
for _, value := range values {
w.Header().Add(header, value)
}
}
}
func (resolver storageResolver) ArtifactsHandler(w http.ResponseWriter, r *http.Request, p *packages.Package) {
nameVersionZip := fmt.Sprintf("%s-%s.zip", p.Name, p.Version)
artifactURL := resolver.artifactsPackagesURL.ResolveReference(&url.URL{Path: nameVersionZip})
resolver.pipeRequestProxy(w, r, artifactURL.String())
}
func (resolver storageResolver) StaticHandler(w http.ResponseWriter, r *http.Request, p *packages.Package, resourcePath string) {
nameVersion := fmt.Sprintf("%s-%s/", p.Name, p.Version)
staticURL := resolver.artifactsStaticURL.
ResolveReference(&url.URL{Path: nameVersion}).
ResolveReference(&url.URL{Path: resourcePath})
resolver.pipeRequestProxy(w, r, staticURL.String())
}
func (resolver storageResolver) SignaturesHandler(w http.ResponseWriter, r *http.Request, p *packages.Package) {
nameVersionSigZip := fmt.Sprintf("%s-%s.zip.sig", p.Name, p.Version)
signatureURL := resolver.artifactsPackagesURL.ResolveReference(&url.URL{Path: nameVersionSigZip})
resolver.pipeRequestProxy(w, r, signatureURL.String())
}
var _ packages.RemoteResolver = new(storageResolver)