// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package http import ( "context" "fmt" "io" "mime" "net/http" "path/filepath" "strconv" "strings" "github.com/blang/semver/v4" "github.com/julienschmidt/httprouter" "github.com/siderolabs/image-service/internal/profile" ) // handleImage handles downloading of boot assets. func (f *Frontend) handleImage(ctx context.Context, w http.ResponseWriter, r *http.Request, p httprouter.Params) error { configurationID := p.ByName("configuration") configuration, err := f.configService.Get(ctx, configurationID) if err != nil { return err } versionTag := p.ByName("version") if !strings.HasPrefix(versionTag, "v") { versionTag = "v" + versionTag } version, err := semver.Parse(versionTag[1:]) if err != nil { return fmt.Errorf("error parsing version: %w", err) } path := p.ByName("path") prof, err := profile.ParseFromPath(path) if err != nil { return fmt.Errorf("error parsing profile from path: %w", err) } prof, err = profile.EnhanceFromConfiguration(prof, configuration, versionTag) if err != nil { return fmt.Errorf("error enhancing profile from configuration: %w", err) } if err = prof.Validate(); err != nil { return fmt.Errorf("error validating profile: %w", err) } asset, err := f.assetBuilder.Build(ctx, prof, version.String()) if err != nil { return err } defer asset.Release() //nolint:errcheck w.Header().Set("Content-Length", strconv.FormatInt(asset.Size(), 10)) if ext := filepath.Ext(path); ext != "" { w.Header().Set("Content-Type", mime.TypeByExtension(ext)) } w.WriteHeader(http.StatusOK) if r.Method == http.MethodHead { return nil } reader, err := asset.Reader() if err != nil { return err } defer reader.Close() //nolint:errcheck _, err = io.Copy(w, reader) return err }