package api import ( "fmt" "mime" "net/http" "os" "path/filepath" "strings" ) func (s *Server) serveCDN(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet && r.Method != http.MethodHead { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } _, rel, err := SplitCDNPath(r.URL.Path) if err != nil { http.NotFound(w, r) return } var entry ResourceEntry var hasEntry bool resourceRoot := "" explicitRelease := false channel := r.URL.Query().Get("channel") releaseID := r.URL.Query().Get("release_id") if channel != "" || releaseID != "" { explicitRelease = true channel, releaseID, selectorErr := releaseSelector(r) if selectorErr != nil { http.Error(w, selectorErr.Error(), http.StatusBadRequest) return } selected, selectErr := s.loadReleaseDistribution(r, channel, releaseID, rel) if selectErr != nil { http.Error(w, selectErr.Error(), http.StatusServiceUnavailable) return } if selected == nil || !selected.Available || selected.ResourceRoot == "" { http.Error(w, "selected release is not distributable", http.StatusConflict) return } resourceRoot = selected.ResourceRoot entry, hasEntry = releaseDistributionEntry(selected, rel) } else { idx := s.index() if idx == nil || idx.ResourceRoot == "" { http.Error(w, "resource root not ready", http.StatusServiceUnavailable) return } summary := idx.Summary() if !summary.Ready { // The cached health fact covers the whole current release. A // locally present target is not enough to serve it as a healthy // immutable artifact. http.Error(w, "current release is not distributable", http.StatusServiceUnavailable) return } resourceRoot = idx.ResourceRoot entry, hasEntry = idx.Lookup(rel) } if !hasEntry || !entry.Present || !entry.SizeMatch { http.NotFound(w, r) return } abs, err := ResolveUnderRoot(resourceRoot, rel, true) if err != nil { http.NotFound(w, r) return } info, err := os.Stat(abs) if err != nil || !info.Mode().IsRegular() { http.NotFound(w, r) return } if explicitRelease && hasEntry && uint64(info.Size()) != entry.Bytes { http.Error(w, "size mismatch with release index", http.StatusConflict) return } if !explicitRelease && entry.Bytes > 0 && uint64(info.Size()) != entry.Bytes { http.Error(w, "size mismatch with release index", http.StatusConflict) return } file, err := os.Open(abs) if err != nil { http.NotFound(w, r) return } defer func() { _ = file.Close() }() w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") w.Header().Set("ETag", cdnETag(entry, hasEntry, info)) w.Header().Set("Content-Type", cdnContentType(abs)) http.ServeContent(w, r, info.Name(), info.ModTime(), file) } func cdnETag(entry ResourceEntry, hasEntry bool, info os.FileInfo) string { if hasEntry && entry.BLAKE3 != "" { return fmt.Sprintf(`"blake3-%s"`, entry.BLAKE3) } return fmt.Sprintf(`W/"%d-%d"`, info.Size(), info.ModTime().UnixNano()) } func cdnContentType(abs string) string { ext := strings.ToLower(filepath.Ext(abs)) if ext == ".json" { return "application/json; charset=utf-8" } if ext == ".hash" { return "text/plain; charset=utf-8" } if detected := mime.TypeByExtension(ext); detected != "" { return detected } return "application/octet-stream" }