mirror of
https://github.com/skidoodle/mediaproxy
synced 2026-04-28 08:27:34 +02:00
fix handling
This commit is contained in:
@@ -52,24 +52,6 @@ func loggingMiddleware(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// isAllowedDomain checks if a host is in the configured whitelist.
|
||||||
func isAllowedDomain(host string, allowedDomains []string) bool {
|
func isAllowedDomain(host string, allowedDomains []string) bool {
|
||||||
if len(allowedDomains) == 0 {
|
if len(allowedDomains) == 0 {
|
||||||
|
|||||||
@@ -166,28 +166,20 @@ func (app *App) handleProxy(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if headResp.StatusCode != http.StatusOK {
|
if headResp.StatusCode != http.StatusOK {
|
||||||
logger.Warn("Origin server returned non-200 status for HEAD request", "status", headResp.StatusCode)
|
logger.Warn("Origin server returned non-200 status for HEAD request", "status", headResp.StatusCode)
|
||||||
http.Error(w, fmt.Sprintf("Media source returned status: %d", headResp.StatusCode), headResp.StatusCode)
|
w.WriteHeader(headResp.StatusCode)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
headerContentType := headResp.Header.Get("Content-Type")
|
headerContentType := headResp.Header.Get("Content-Type")
|
||||||
if !isAllowedType(headerContentType, true) {
|
|
||||||
logger.Warn("Unsupported content type in header", "content_type", headerContentType)
|
|
||||||
http.Error(w, fmt.Sprintf("Unsupported content type from header: %s", headerContentType), http.StatusUnsupportedMediaType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mediaTypeCategory := strings.Split(headerContentType, "/")[0]
|
mediaTypeCategory := strings.Split(headerContentType, "/")[0]
|
||||||
|
|
||||||
switch mediaTypeCategory {
|
switch mediaTypeCategory {
|
||||||
case "image":
|
case "image":
|
||||||
logger.Debug("Delegating to image handler")
|
logger.Debug("Delegating to image handler")
|
||||||
app.handleImage(w, r, mediaURL)
|
app.handleImage(w, r, mediaURL)
|
||||||
case "video", "audio":
|
|
||||||
logger.Debug("Delegating to stream handler")
|
|
||||||
app.handleStream(w, r, mediaURL)
|
|
||||||
default:
|
default:
|
||||||
logger.Warn("Media type passed initial checks but is not an image, video, or audio", "category", mediaTypeCategory)
|
logger.Debug("Passing through unhandled content type", "content_type", headerContentType)
|
||||||
http.Error(w, "Unsupported media type", http.StatusUnsupportedMediaType)
|
app.handleStream(w, r, mediaURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,34 +209,52 @@ func (app *App) handleImage(w http.ResponseWriter, r *http.Request, mediaURL str
|
|||||||
|
|
||||||
mtype := mimetype.Detect(mediaData)
|
mtype := mimetype.Detect(mediaData)
|
||||||
if !strings.HasPrefix(mtype.String(), "image/") {
|
if !strings.HasPrefix(mtype.String(), "image/") {
|
||||||
logger.Warn("Content sniffing detected non-image type after HEAD request", "sniffed_type", mtype.String())
|
logger.Warn("Content sniffing detected non-image type; passing through", "sniffed_type", mtype.String())
|
||||||
http.Error(w, "Content sniffing detected non-image type", http.StatusUnsupportedMediaType)
|
w.Header().Set("Content-Type", mtype.String())
|
||||||
|
w.Write(mediaData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var entryToCache CacheEntry
|
|
||||||
isAnimated := false
|
|
||||||
if mtype.Is("image/gif") {
|
if mtype.Is("image/gif") {
|
||||||
var gifErr error
|
isAnimated, _ := isGif(mediaData)
|
||||||
isAnimated, gifErr = isGif(mediaData)
|
|
||||||
if gifErr != nil {
|
|
||||||
logger.Warn("Could not determine GIF animation, treating as static", "error", gifErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isAnimated {
|
if isAnimated {
|
||||||
entryToCache = CacheEntry{ContentType: mtype.String(), Data: mediaData}
|
logger.Debug("Passing through animated GIF")
|
||||||
} else {
|
entryToCache := CacheEntry{ContentType: mtype.String(), Data: mediaData}
|
||||||
optimizedImage, err := optimizeMedia(mediaData, app.Config.DefaultImageQuality)
|
app.Cache.SetWithTTL(mediaURL, entryToCache, int64(len(mediaData)), app.Config.CacheTTL)
|
||||||
if err != nil {
|
w.Header().Set("Content-Type", entryToCache.ContentType)
|
||||||
logger.Error("Failed to process image", "error", err)
|
w.Write(entryToCache.Data)
|
||||||
http.Error(w, "Could not process image", http.StatusInternalServerError)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
entryToCache = CacheEntry{ContentType: "image/webp", Data: optimizedImage}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Cache.SetWithTTL(mediaURL, entryToCache, int64(len(entryToCache.Data)), app.Config.CacheTTL)
|
if mtype.Is("image/ico") || mtype.Is("image/svg+xml") || mtype.Is("image/x-icon") {
|
||||||
|
logger.Debug("Passing through unsupported image type", "type", mtype.String())
|
||||||
|
entryToCache := CacheEntry{ContentType: mtype.String(), Data: mediaData}
|
||||||
|
app.Cache.SetWithTTL(mediaURL, entryToCache, int64(len(mediaData)), app.Config.CacheTTL)
|
||||||
|
w.Header().Set("Content-Type", entryToCache.ContentType)
|
||||||
|
w.Write(entryToCache.Data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
optimizedImage, err := optimizeMedia(mediaData, app.Config.DefaultImageQuality)
|
||||||
|
|
||||||
|
if err != nil || len(optimizedImage) >= len(mediaData) {
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("Could not process image, serving original", "error", err)
|
||||||
|
} else {
|
||||||
|
logger.Debug("Optimized image was larger than original, serving original")
|
||||||
|
}
|
||||||
|
|
||||||
|
entryToCache := CacheEntry{ContentType: mtype.String(), Data: mediaData}
|
||||||
|
app.Cache.SetWithTTL(mediaURL, entryToCache, int64(len(mediaData)), app.Config.CacheTTL)
|
||||||
|
w.Header().Set("Content-Type", entryToCache.ContentType)
|
||||||
|
w.Write(entryToCache.Data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("Successfully optimized image", "original_size", len(mediaData), "optimized_size", len(optimizedImage))
|
||||||
|
entryToCache := CacheEntry{ContentType: "image/webp", Data: optimizedImage}
|
||||||
|
app.Cache.SetWithTTL(mediaURL, entryToCache, int64(len(optimizedImage)), app.Config.CacheTTL)
|
||||||
app.Cache.Wait()
|
app.Cache.Wait()
|
||||||
|
|
||||||
w.Header().Set("Content-Type", entryToCache.ContentType)
|
w.Header().Set("Content-Type", entryToCache.ContentType)
|
||||||
|
|||||||
Reference in New Issue
Block a user