package dav import ( "encoding/xml" "fmt" "log" "net/http" "path" "strings" "github.com/debridmediamanager.com/zurg/internal/config" "github.com/debridmediamanager.com/zurg/internal/torrent" "github.com/debridmediamanager.com/zurg/pkg/dav" "github.com/hashicorp/golang-lru/v2/expirable" ) func HandlePropfindRequest(w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager, c config.ConfigInterface, cache *expirable.LRU[string, string]) { requestPath := path.Clean(r.URL.Path) requestPath = strings.Trim(requestPath, "/") if data, exists := cache.Get(requestPath); exists { w.Header().Set("Content-Type", "text/xml; charset=\"utf-8\"") w.WriteHeader(http.StatusMultiStatus) fmt.Fprint(w, data) return } var output []byte var err error filteredSegments := strings.Split(requestPath, "/") switch { case len(filteredSegments) == 1 && filteredSegments[0] == "": output, err = handleRoot(w, r, c) case len(filteredSegments) == 1: output, err = handleListOfTorrents(requestPath, w, r, t, c) case len(filteredSegments) == 2: output, err = handleSingleTorrent(requestPath, w, r, t) default: writeHTTPError(w, "Not Found", http.StatusNotFound) return } if err != nil { log.Printf("Error processing request: %v\n", err) writeHTTPError(w, "Server error", http.StatusInternalServerError) return } if output != nil { respBody := fmt.Sprintf("\n%s\n", output) cache.Add(requestPath, respBody) w.Header().Set("Content-Type", "text/xml; charset=\"utf-8\"") w.WriteHeader(http.StatusMultiStatus) fmt.Fprint(w, respBody) } } func handleRoot(w http.ResponseWriter, r *http.Request, c config.ConfigInterface) ([]byte, error) { var responses []dav.Response responses = append(responses, dav.Directory("/")) for _, directory := range c.GetDirectories() { responses = append(responses, dav.Directory("/"+directory)) } rootResponse := dav.MultiStatus{ XMLNS: "DAV:", Response: responses, } return xml.Marshal(rootResponse) } func handleListOfTorrents(requestPath string, w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager, c config.ConfigInterface) ([]byte, error) { basePath := path.Base(requestPath) for _, directory := range c.GetDirectories() { if basePath == directory { torrents := t.GetByDirectory(basePath) resp, err := createMultiTorrentResponse("/"+basePath, torrents) if err != nil { return nil, fmt.Errorf("cannot read directory (%s): %w", basePath, err) } return xml.Marshal(resp) } } return nil, fmt.Errorf("cannot find directory when generating list: %s", requestPath) } func handleSingleTorrent(requestPath string, w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager) ([]byte, error) { directory := path.Dir(requestPath) torrentName := path.Base(requestPath) sameNameTorrents := findAllTorrentsWithName(t, directory, torrentName) if len(sameNameTorrents) == 0 { return nil, fmt.Errorf("cannot find directory when generating single torrent: %s", requestPath) } resp, err := createSingleTorrentResponse("/"+directory, sameNameTorrents) if err != nil { return nil, fmt.Errorf("cannot read directory (%s): %w", requestPath, err) } return xml.Marshal(resp) } func writeHTTPError(w http.ResponseWriter, errorMessage string, statusCode int) { log.Println(errorMessage) http.Error(w, errorMessage, statusCode) }