mirror of
https://github.com/skidoodle/mediaproxy
synced 2025-10-14 09:45:09 +02:00
first commit
This commit is contained in:
107
helper.go
Normal file
107
helper.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"image/gif"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/h2non/bimg"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const loggerKey contextKey = "logger"
|
||||
|
||||
type responseWriter struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
func (rw *responseWriter) WriteHeader(code int) {
|
||||
rw.statusCode = code
|
||||
rw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// loggingMiddleware injects a contextual logger into the request and logs request metrics.
|
||||
func loggingMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
requestID := strconv.FormatInt(time.Now().UnixNano(), 36)
|
||||
logger := slog.With(
|
||||
"request_id", requestID,
|
||||
"method", r.Method,
|
||||
"path", r.URL.Path,
|
||||
"remote_addr", r.RemoteAddr,
|
||||
)
|
||||
ctx := context.WithValue(r.Context(), loggerKey, logger)
|
||||
rw := &responseWriter{ResponseWriter: w, statusCode: http.StatusOK}
|
||||
next.ServeHTTP(rw, r.WithContext(ctx))
|
||||
|
||||
statusText := fmt.Sprintf("%d %s", rw.statusCode, http.StatusText(rw.statusCode))
|
||||
logger.Info("Handled request",
|
||||
"status", statusText,
|
||||
"duration", time.Since(start).String(),
|
||||
"user_agent", r.UserAgent(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// isAllowedType performs a categorical check for 'image/*', 'video/*', and 'audio/*'.
|
||||
func isAllowedType(mimeType string, allowGeneric bool) bool {
|
||||
mimeType = strings.Split(mimeType, ";")[0]
|
||||
category := strings.Split(mimeType, "/")[0]
|
||||
|
||||
switch category {
|
||||
case "image", "video", "audio":
|
||||
return true
|
||||
}
|
||||
|
||||
// Allow generic binary streams on the initial HEAD request, forcing the
|
||||
// more reliable content sniffing to make the final decision.
|
||||
if allowGeneric && mimeType == "application/octet-stream" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isAllowedDomain checks if a host is in the configured whitelist.
|
||||
func isAllowedDomain(host string, allowedDomains []string) bool {
|
||||
if len(allowedDomains) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, domain := range allowedDomains {
|
||||
if host == domain || strings.HasSuffix(host, "."+domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isGif checks if the provided byte slice represents an animated GIF.
|
||||
func isGif(data []byte) (bool, error) {
|
||||
r := bytes.NewReader(data)
|
||||
g, err := gif.DecodeAll(r)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return len(g.Image) > 1, nil
|
||||
}
|
||||
|
||||
// optimizeMedia converts a static image to WebP and applies a quality setting.
|
||||
func optimizeMedia(data []byte, quality int) ([]byte, error) {
|
||||
webp, err := bimg.NewImage(data).Convert(bimg.WEBP)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert image to webp: %w", err)
|
||||
}
|
||||
processed, err := bimg.NewImage(webp).Process(bimg.Options{Quality: quality})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to process image quality: %w", err)
|
||||
}
|
||||
return processed, nil
|
||||
}
|
||||
Reference in New Issue
Block a user