package dav import ( "encoding/xml" "fmt" "net/http" "path" "path/filepath" "sort" "strings" "github.com/debridmediamanager.com/zurg/internal/config" "github.com/debridmediamanager.com/zurg/internal/torrent" "github.com/debridmediamanager.com/zurg/pkg/dav" "github.com/debridmediamanager.com/zurg/pkg/logutil" ) func HandlePropfindRequest(w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager, c config.ConfigInterface) { log := logutil.NewLogger().Named("dav") requestPath := path.Clean(r.URL.Path) requestPath = strings.Trim(requestPath, "/") var output []byte var err error filteredSegments := strings.Split(requestPath, "/") switch { case len(filteredSegments) == 1 && filteredSegments[0] == "": output, err = handleRoot(c) case len(filteredSegments) == 1: output, err = handleListOfTorrents(requestPath, t) case len(filteredSegments) == 2: output, err = handleSingleTorrent(requestPath, t) default: log.Warnf("Request %s %s not found", r.Method, requestPath) http.Error(w, "Not Found", http.StatusNotFound) return } if err != nil { if strings.Contains(err.Error(), "cannot find") { http.Error(w, "Not Found", http.StatusNotFound) return } log.Errorf("Error processing request: %v", err) http.Error(w, "Server error", http.StatusInternalServerError) return } if output != nil { respBody := fmt.Sprintf("\n%s\n", output) w.Header().Set("Content-Type", "text/xml; charset=\"utf-8\"") w.WriteHeader(http.StatusMultiStatus) fmt.Fprint(w, respBody) } } func handleRoot(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, t *torrent.TorrentManager) ([]byte, error) { basePath := path.Base(requestPath) torrents, ok := t.DirectoryMap.Get(basePath) if !ok { return nil, fmt.Errorf("cannot find directory %s", basePath) } var responses []dav.Response // initial response is the directory itself responses = append(responses, dav.Directory(basePath+"/")) accessKeys := torrents.Keys() sort.Strings(accessKeys) for _, accessKey := range accessKeys { responses = append(responses, dav.Directory(filepath.Join(basePath, accessKey))) } resp := &dav.MultiStatus{ XMLNS: "DAV:", Response: responses, } return xml.Marshal(resp) } func handleSingleTorrent(requestPath string, t *torrent.TorrentManager) ([]byte, error) { basePath := path.Base(path.Dir(requestPath)) torrents, ok := t.DirectoryMap.Get(basePath) if !ok { return nil, fmt.Errorf("cannot find directory %s", basePath) } accessKey := path.Base(requestPath) tor, ok := torrents.Get(accessKey) if !ok { return nil, fmt.Errorf("cannot find torrent %s", accessKey) } var responses []dav.Response // initial response is the directory itself responses = append(responses, dav.Directory(requestPath+"/")) filenames := tor.SelectedFiles.Keys() sort.Strings(filenames) for _, filename := range filenames { file, _ := tor.SelectedFiles.Get(filename) if file == nil || file.Link == "" { continue } responses = append(responses, dav.File( filepath.Join(requestPath, filename), file.Bytes, convertRFC3339toRFC1123(tor.LatestAdded), file.Link, )) } resp := &dav.MultiStatus{ XMLNS: "DAV:", Response: responses, } return xml.Marshal(resp) }