package dav import ( "encoding/xml" "fmt" "net/http" "path" "path/filepath" "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(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: 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(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 { var responses []dav.Response responses = append(responses, dav.Directory(basePath)) for el := t.TorrentMap.Front(); el != nil; el = el.Next() { accessKey := el.Key torrent := el.Value if torrent.InProgress { continue } for _, dir := range torrent.Directories { if dir == basePath { path := filepath.Join(basePath, accessKey) responses = append(responses, dav.Directory(path)) break } } } resp := &dav.MultiStatus{ XMLNS: "DAV:", Response: responses, } 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) { accessKey := path.Base(requestPath) torrent, exists := t.TorrentMap.Get(accessKey) if !exists { 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)) for el := torrent.SelectedFiles.Front(); el != nil; el = el.Next() { file := el.Value if file.Link == "" { // will be caught by torrent manager's repairAll // just skip it for now continue } filename := filepath.Base(file.Path) filePath := filepath.Join(requestPath, filename) responses = append(responses, dav.File( filePath, file.Bytes, convertRFC3339toRFC1123(torrent.LatestAdded), file.Link, )) } resp := &dav.MultiStatus{ XMLNS: "DAV:", Response: responses, } return xml.Marshal(resp) }