diff --git a/internal/dav/listing.go b/internal/dav/listing.go
index e8c79e4..efd97e9 100644
--- a/internal/dav/listing.go
+++ b/internal/dav/listing.go
@@ -1,7 +1,6 @@
package dav
import (
- "encoding/xml"
"fmt"
"net/http"
"path"
@@ -20,18 +19,17 @@ func HandlePropfindRequest(w http.ResponseWriter, r *http.Request, t *torrent.To
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(t)
+ err = handleRoot(w, t)
case len(filteredSegments) == 1:
- output, err = handleListOfTorrents(requestPath, t)
+ err = handleListOfTorrents(w, requestPath, t)
case len(filteredSegments) == 2:
- output, err = handleSingleTorrent(requestPath, t)
+ err = handleSingleTorrent(w, requestPath, t)
default:
log.Warnf("Request %s %s not found", r.Method, requestPath)
http.Error(w, "Not Found", http.StatusNotFound)
@@ -48,68 +46,67 @@ func HandlePropfindRequest(w http.ResponseWriter, r *http.Request, t *torrent.To
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)
- }
+ w.Header().Set("Content-Type", "text/xml; charset=\"utf-8\"")
}
-func handleRoot(t *torrent.TorrentManager) ([]byte, error) {
- var responses []dav.Response
- responses = append(responses, dav.Directory(""))
+func handleRoot(w http.ResponseWriter, t *torrent.TorrentManager) error {
+ fmt.Fprint(w, "")
+ // initial response is the directory itself
+ fmt.Fprint(w, dav.Directory("", ""))
directories := t.DirectoryMap.Keys()
sort.Strings(directories)
for _, directory := range directories {
- responses = append(responses, dav.Directory(directory))
+ fmt.Fprint(w, dav.Directory(directory, ""))
}
- rootResponse := dav.MultiStatus{
- XMLNS: "DAV:",
- Response: responses,
- }
- return xml.Marshal(rootResponse)
+
+ fmt.Fprint(w, "")
+ return nil
}
-func handleListOfTorrents(requestPath string, t *torrent.TorrentManager) ([]byte, error) {
+func handleListOfTorrents(w http.ResponseWriter, requestPath string, t *torrent.TorrentManager) error {
basePath := path.Base(requestPath)
torrents, ok := t.DirectoryMap.Get(basePath)
if !ok {
- return nil, fmt.Errorf("cannot find directory %s", basePath)
+ return fmt.Errorf("cannot find directory %s", basePath)
}
- var responses []dav.Response
+
+ fmt.Fprint(w, "")
// initial response is the directory itself
- responses = append(responses, dav.Directory(basePath+"/"))
+ fmt.Fprint(w, dav.Directory(basePath+"/", ""))
- accessKeys := torrents.Keys()
- sort.Strings(accessKeys)
- for _, accessKey := range accessKeys {
- responses = append(responses, dav.Directory(filepath.Join(basePath, accessKey)))
+ var allTorrents []*torrent.Torrent
+ torrents.IterCb(func(_ string, tor *torrent.Torrent) {
+ allTorrents = append(allTorrents, tor)
+ })
+ sort.Slice(allTorrents, func(i, j int) bool {
+ return allTorrents[i].AccessKey < allTorrents[j].AccessKey
+ })
+
+ for _, tor := range allTorrents {
+ fmt.Fprint(w, dav.Directory(filepath.Join(basePath, tor.AccessKey), tor.LatestAdded))
}
- resp := &dav.MultiStatus{
- XMLNS: "DAV:",
- Response: responses,
- }
- return xml.Marshal(resp)
+ fmt.Fprint(w, "")
+ return nil
}
-func handleSingleTorrent(requestPath string, t *torrent.TorrentManager) ([]byte, error) {
+func handleSingleTorrent(w http.ResponseWriter, requestPath string, t *torrent.TorrentManager) error {
basePath := path.Base(path.Dir(requestPath))
torrents, ok := t.DirectoryMap.Get(basePath)
if !ok {
- return nil, fmt.Errorf("cannot find directory %s", basePath)
+ return 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)
+ return fmt.Errorf("cannot find torrent %s", accessKey)
}
- var responses []dav.Response
+ fmt.Fprint(w, "")
// initial response is the directory itself
- responses = append(responses, dav.Directory(requestPath+"/"))
+ fmt.Fprint(w, dav.Directory(requestPath+"/", tor.LatestAdded))
+
filenames := tor.SelectedFiles.Keys()
sort.Strings(filenames)
for _, filename := range filenames {
@@ -117,16 +114,9 @@ func handleSingleTorrent(requestPath string, t *torrent.TorrentManager) ([]byte,
if file == nil || !strings.HasPrefix(file.Link, "http") {
continue
}
- responses = append(responses, dav.File(
- filepath.Join(requestPath, filename),
- file.Bytes,
- convertRFC3339toRFC1123(tor.LatestAdded),
- file.Link,
- ))
+ fmt.Fprint(w, dav.File(filepath.Join(requestPath, filename), file.Bytes, tor.LatestAdded))
}
- resp := &dav.MultiStatus{
- XMLNS: "DAV:",
- Response: responses,
- }
- return xml.Marshal(resp)
+
+ fmt.Fprint(w, "")
+ return nil
}
diff --git a/pkg/dav/response.go b/pkg/dav/response.go
index 21ee25a..33079db 100644
--- a/pkg/dav/response.go
+++ b/pkg/dav/response.go
@@ -1,27 +1,39 @@
package dav
-func Directory(path string) Response {
+import "fmt"
+
+func DavDirectory(path, added string) Response {
return Response{
Href: "/" + customPathEscape(path),
Propstat: PropStat{
Prop: Prop{
ResourceType: ResourceType{Value: ""},
+ LastModified: added,
},
Status: "HTTP/1.1 200 OK",
},
}
}
-func File(path string, fileSize int64, added string, link string) Response {
+func DavFile(path string, fileSize int64, added string, link string) Response {
return Response{
Href: "/" + customPathEscape(path),
Propstat: PropStat{
Prop: Prop{
ContentLength: fileSize,
- CreationDate: added,
LastModified: added,
},
Status: "HTTP/1.1 200 OK",
},
}
}
+
+// optimized versions, no more marshalling
+
+func Directory(path, added string) string {
+ return fmt.Sprintf("/%s%sHTTP/1.1 200 OK", customPathEscape(path), added)
+}
+
+func File(path string, fileSize int64, added string) string {
+ return fmt.Sprintf("/%s%d%sHTTP/1.1 200 OK", customPathEscape(path), fileSize, added)
+}
diff --git a/pkg/dav/types.go b/pkg/dav/types.go
index 352df72..07d0e5b 100644
--- a/pkg/dav/types.go
+++ b/pkg/dav/types.go
@@ -23,7 +23,6 @@ type PropStat struct {
type Prop struct {
ResourceType ResourceType `xml:"d:resourcetype"`
ContentLength int64 `xml:"d:getcontentlength,omitempty"`
- CreationDate string `xml:"d:creationdate,omitempty"`
LastModified string `xml:"d:getlastmodified,omitempty"`
}