package handlers import ( "net/http" "path" "path/filepath" "strconv" "strings" "github.com/owncast/owncast/config" "github.com/owncast/owncast/core" "github.com/owncast/owncast/core/data" "github.com/owncast/owncast/models" "github.com/owncast/owncast/utils" "github.com/owncast/owncast/webserver/middleware" ) // HandleHLSRequest will manage all requests to HLS content. func (h *Handlers) HandleHLSRequest(w http.ResponseWriter, r *http.Request) { // Sanity check to limit requests to HLS file types. if filepath.Ext(r.URL.Path) != ".m3u8" && filepath.Ext(r.URL.Path) != ".ts" { w.WriteHeader(http.StatusNotFound) return } requestedPath := r.URL.Path relativePath := strings.Replace(requestedPath, "/hls/", "", 1) fullPath := filepath.Join(config.HLSStoragePath, relativePath) // If using external storage then only allow requests for the // master playlist at stream.m3u8, no variants or segments. if data.GetS3Config().Enabled && relativePath != "stream.m3u8" { w.WriteHeader(http.StatusNotFound) return } // Handle playlists if path.Ext(r.URL.Path) == ".m3u8" { // Playlists should never be cached. middleware.DisableCache(w) // Force the correct content type w.Header().Set("Content-Type", "application/x-mpegURL") // Use this as an opportunity to mark this viewer as active. viewer := models.GenerateViewerFromRequest(r) core.SetViewerActive(&viewer) } else { cacheTime := utils.GetCacheDurationSecondsForPath(relativePath) w.Header().Set("Cache-Control", "public, max-age="+strconv.Itoa(cacheTime)) } middleware.EnableCors(w) http.ServeFile(w, r, fullPath) }