internal/pkg/api/handleFileDelivery.go (56 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;
// you may not use this file except in compliance with the Elastic License.
package api
import (
"errors"
"net/http"
"strconv"
"github.com/rs/zerolog"
"github.com/elastic/fleet-server/v7/internal/pkg/bulk"
"github.com/elastic/fleet-server/v7/internal/pkg/cache"
"github.com/elastic/fleet-server/v7/internal/pkg/config"
"github.com/elastic/fleet-server/v7/internal/pkg/file/delivery"
"github.com/elastic/fleet-server/v7/internal/pkg/model"
"github.com/elastic/go-elasticsearch/v8"
)
type FileDeliveryT struct {
bulker bulk.Bulk
cache cache.Cache
deliverer *delivery.Deliverer
authAgent func(*http.Request, *string, bulk.Bulk, cache.Cache) (*model.Agent, error) // injectable for testing purposes
}
func NewFileDeliveryT(cfg *config.Server, bulker bulk.Bulk, chunkClient *elasticsearch.Client, cache cache.Cache) *FileDeliveryT {
return &FileDeliveryT{
bulker: bulker,
cache: cache,
deliverer: delivery.New(chunkClient, bulker, maxFileSize),
authAgent: authAgent,
}
}
func (ft *FileDeliveryT) handleSendFile(zlog zerolog.Logger, w http.ResponseWriter, r *http.Request, fileID string) error {
agent, err := ft.authAgent(r, nil, ft.bulker, ft.cache)
if err != nil {
return err
}
// find file
info, err := ft.deliverer.FindFileForAgent(r.Context(), fileID, agent.Agent.ID)
if err != nil {
return err
}
chunks, err := ft.deliverer.LocateChunks(r.Context(), zlog, fileID)
if errors.Is(err, delivery.ErrNoFile) {
w.WriteHeader(http.StatusNotFound)
return err
}
if err != nil {
return err
}
// set headers before writing any chunks!
// if mime_type was provided, set as Content-Type, otherwise fall back to octet-stream
w.Header().Set("Content-Type", "application/octet-stream")
if info.File.MimeType != "" {
w.Header().Set("Content-Type", info.File.MimeType)
}
if info.File.Size > 0 {
w.Header().Set("Content-Length", strconv.FormatInt(info.File.Size, 10))
}
if info.File.Hash != nil && info.File.Hash.SHA2 != "" {
w.Header().Set("X-File-SHA2", info.File.Hash.SHA2)
}
// stream the chunks out
return ft.deliverer.SendFile(r.Context(), zlog, w, chunks, fileID)
}