Andrey Smirnov a4aa38c9ec
feat: implement PXE frontend
Also, improve error reporting and add more tests for invalid requests.

Fixes #7

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
2023-09-01 23:05:00 +04:00

88 lines
1.9 KiB
Go

// 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
}