feat: update WebDAV download handler to support range requests and improve response handling
This commit is contained in:
@@ -1418,13 +1418,13 @@ func downloadOrgFileHandler(w http.ResponseWriter, r *http.Request, db *database
|
|||||||
// Download from user's Nextcloud space under /orgs/<orgID>/
|
// Download from user's Nextcloud space under /orgs/<orgID>/
|
||||||
rel := strings.TrimPrefix(filePath, "/")
|
rel := strings.TrimPrefix(filePath, "/")
|
||||||
remotePath := path.Join("/orgs", orgID.String(), rel)
|
remotePath := path.Join("/orgs", orgID.String(), rel)
|
||||||
reader, size, err := storageClient.Download(r.Context(), remotePath)
|
resp, err := storageClient.Download(r.Context(), remotePath, r.Header.Get("Range"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogError(r, err, "Failed to download from Nextcloud")
|
errors.LogError(r, err, "Failed to download from Nextcloud")
|
||||||
errors.WriteError(w, errors.CodeNotFound, "File not found", http.StatusNotFound)
|
errors.WriteError(w, errors.CodeNotFound, "File not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Set appropriate headers for inline viewing
|
// Set appropriate headers for inline viewing
|
||||||
fileName := path.Base(filePath)
|
fileName := path.Base(filePath)
|
||||||
@@ -1438,13 +1438,25 @@ func downloadOrgFileHandler(w http.ResponseWriter, r *http.Request, db *database
|
|||||||
contentType = "image/jpeg"
|
contentType = "image/jpeg"
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", fileName))
|
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", fileName))
|
||||||
w.Header().Set("Content-Type", contentType)
|
if ct := resp.Header.Get("Content-Type"); ct != "" {
|
||||||
if size > 0 {
|
w.Header().Set("Content-Type", ct)
|
||||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
|
} else {
|
||||||
|
w.Header().Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
|
if cr := resp.Header.Get("Content-Range"); cr != "" {
|
||||||
|
w.Header().Set("Content-Range", cr)
|
||||||
|
}
|
||||||
|
if cl := resp.Header.Get("Content-Length"); cl != "" {
|
||||||
|
w.Header().Set("Content-Length", cl)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusPartialContent {
|
||||||
|
w.WriteHeader(http.StatusPartialContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream the file
|
// Stream the file
|
||||||
io.Copy(w, reader)
|
io.Copy(w, resp.Body)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1481,13 +1493,13 @@ func downloadUserFileHandler(w http.ResponseWriter, r *http.Request, db *databas
|
|||||||
remotePath := strings.TrimPrefix(filePath, "/")
|
remotePath := strings.TrimPrefix(filePath, "/")
|
||||||
fmt.Printf("[DEBUG] Downloading from user WebDAV: /%s\n", remotePath)
|
fmt.Printf("[DEBUG] Downloading from user WebDAV: /%s\n", remotePath)
|
||||||
|
|
||||||
reader, size, err := storageClient.Download(r.Context(), "/"+remotePath)
|
resp, err := storageClient.Download(r.Context(), "/"+remotePath, r.Header.Get("Range"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogError(r, err, "Failed to download from Nextcloud")
|
errors.LogError(r, err, "Failed to download from Nextcloud")
|
||||||
errors.WriteError(w, errors.CodeNotFound, "File not found", http.StatusNotFound)
|
errors.WriteError(w, errors.CodeNotFound, "File not found", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer reader.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Set appropriate headers for inline viewing
|
// Set appropriate headers for inline viewing
|
||||||
fileName := path.Base(filePath)
|
fileName := path.Base(filePath)
|
||||||
@@ -1501,12 +1513,24 @@ func downloadUserFileHandler(w http.ResponseWriter, r *http.Request, db *databas
|
|||||||
contentType = "image/jpeg"
|
contentType = "image/jpeg"
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", fileName))
|
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", fileName))
|
||||||
w.Header().Set("Content-Type", contentType)
|
if ct := resp.Header.Get("Content-Type"); ct != "" {
|
||||||
if size > 0 {
|
w.Header().Set("Content-Type", ct)
|
||||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
|
} else {
|
||||||
|
w.Header().Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
w.Header().Set("Accept-Ranges", "bytes")
|
||||||
|
if cr := resp.Header.Get("Content-Range"); cr != "" {
|
||||||
|
w.Header().Set("Content-Range", cr)
|
||||||
|
}
|
||||||
|
if cl := resp.Header.Get("Content-Length"); cl != "" {
|
||||||
|
w.Header().Set("Content-Length", cl)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusPartialContent {
|
||||||
|
w.WriteHeader(http.StatusPartialContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stream the file
|
// Stream the file
|
||||||
io.Copy(w, reader)
|
io.Copy(w, resp.Body)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,9 +124,9 @@ func (c *WebDAVClient) Upload(ctx context.Context, remotePath string, r io.Reade
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download retrieves a file from the remotePath using HTTP GET (WebDAV).
|
// Download retrieves a file from the remotePath using HTTP GET (WebDAV).
|
||||||
func (c *WebDAVClient) Download(ctx context.Context, remotePath string) (io.ReadCloser, int64, error) {
|
func (c *WebDAVClient) Download(ctx context.Context, remotePath string, rangeHeader string) (*http.Response, error) {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return nil, 0, fmt.Errorf("no webdav client configured")
|
return nil, fmt.Errorf("no webdav client configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
rel := strings.TrimLeft(remotePath, "/")
|
rel := strings.TrimLeft(remotePath, "/")
|
||||||
@@ -146,24 +146,27 @@ func (c *WebDAVClient) Download(ctx context.Context, remotePath string) (io.Read
|
|||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", full, nil)
|
req, err := http.NewRequestWithContext(ctx, "GET", full, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if c.user != "" {
|
if c.user != "" {
|
||||||
req.SetBasicAuth(c.user, c.pass)
|
req.SetBasicAuth(c.user, c.pass)
|
||||||
}
|
}
|
||||||
|
if rangeHeader != "" {
|
||||||
|
req.Header.Set("Range", rangeHeader)
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
resp, err := c.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||||
return resp.Body, resp.ContentLength, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
return nil, 0, fmt.Errorf("webdav download failed: %d %s", resp.StatusCode, string(body))
|
resp.Body.Close()
|
||||||
|
return nil, fmt.Errorf("webdav download failed: %d %s", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes a file or collection from the remotePath using HTTP DELETE (WebDAV).
|
// Delete removes a file or collection from the remotePath using HTTP DELETE (WebDAV).
|
||||||
|
|||||||
Reference in New Issue
Block a user