diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/github.com/matrix-org/dendrite/mediaapi/types/types.go | 5 | ||||
-rw-r--r-- | src/github.com/matrix-org/dendrite/mediaapi/writers/download.go | 278 |
2 files changed, 147 insertions, 136 deletions
diff --git a/src/github.com/matrix-org/dendrite/mediaapi/types/types.go b/src/github.com/matrix-org/dendrite/mediaapi/types/types.go index 26b09e4f..c7e5860d 100644 --- a/src/github.com/matrix-org/dendrite/mediaapi/types/types.go +++ b/src/github.com/matrix-org/dendrite/mediaapi/types/types.go @@ -19,7 +19,6 @@ import ( "github.com/matrix-org/dendrite/common/config" "github.com/matrix-org/gomatrixserverlib" - "github.com/matrix-org/util" ) // FileSizeBytes is a file size in bytes @@ -67,8 +66,8 @@ type RemoteRequestResult struct { Cond *sync.Cond // MediaMetadata of the requested file to avoid querying the database for every waiting routine MediaMetadata *MediaMetadata - // An error in util.JSONResponse form. nil in case of no error. - ErrorResponse *util.JSONResponse + // An error, nil in case of no error. + Error error } // ActiveRemoteRequests is a lockable map of media URIs requested from remote homeservers diff --git a/src/github.com/matrix-org/dendrite/mediaapi/writers/download.go b/src/github.com/matrix-org/dendrite/mediaapi/writers/download.go index 8066327c..926d2fbe 100644 --- a/src/github.com/matrix-org/dendrite/mediaapi/writers/download.go +++ b/src/github.com/matrix-org/dendrite/mediaapi/writers/download.go @@ -36,6 +36,7 @@ import ( "github.com/matrix-org/dendrite/mediaapi/types" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" + "github.com/pkg/errors" ) const mediaIDCharacters = "A-Za-z0-9_=-" @@ -59,8 +60,18 @@ type downloadRequest struct { // If they are present in the cache, they are served directly. // If they are not present in the cache, they are obtained from the remote server and // simultaneously served back to the client and written into the cache. -func Download(w http.ResponseWriter, req *http.Request, origin gomatrixserverlib.ServerName, mediaID types.MediaID, cfg *config.Dendrite, db *storage.Database, activeRemoteRequests *types.ActiveRemoteRequests, activeThumbnailGeneration *types.ActiveThumbnailGeneration, isThumbnailRequest bool) { - r := &downloadRequest{ +func Download( + w http.ResponseWriter, + req *http.Request, + origin gomatrixserverlib.ServerName, + mediaID types.MediaID, + cfg *config.Dendrite, + db *storage.Database, + activeRemoteRequests *types.ActiveRemoteRequests, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, + isThumbnailRequest bool, +) { + dReq := &downloadRequest{ MediaMetadata: &types.MediaMetadata{ MediaID: mediaID, Origin: origin, @@ -72,7 +83,7 @@ func Download(w http.ResponseWriter, req *http.Request, origin gomatrixserverlib }), } - if r.IsThumbnailRequest { + if dReq.IsThumbnailRequest { width, err := strconv.Atoi(req.FormValue("width")) if err != nil { width = -1 @@ -81,36 +92,47 @@ func Download(w http.ResponseWriter, req *http.Request, origin gomatrixserverlib if err != nil { height = -1 } - r.ThumbnailSize = types.ThumbnailSize{ + dReq.ThumbnailSize = types.ThumbnailSize{ Width: width, Height: height, ResizeMethod: strings.ToLower(req.FormValue("method")), } - r.Logger.WithFields(log.Fields{ - "RequestedWidth": r.ThumbnailSize.Width, - "RequestedHeight": r.ThumbnailSize.Height, - "RequestedResizeMethod": r.ThumbnailSize.ResizeMethod, + dReq.Logger.WithFields(log.Fields{ + "RequestedWidth": dReq.ThumbnailSize.Width, + "RequestedHeight": dReq.ThumbnailSize.Height, + "RequestedResizeMethod": dReq.ThumbnailSize.ResizeMethod, }) } // request validation if req.Method != "GET" { - r.jsonErrorResponse(w, util.JSONResponse{ + dReq.jsonErrorResponse(w, util.JSONResponse{ Code: 405, JSON: jsonerror.Unknown("request method must be GET"), }) return } - if resErr := r.Validate(); resErr != nil { - r.jsonErrorResponse(w, *resErr) + if resErr := dReq.Validate(); resErr != nil { + dReq.jsonErrorResponse(w, *resErr) + return + } + + metadata, err := dReq.doDownload(w, cfg, db, activeRemoteRequests, activeThumbnailGeneration) + if err != nil { + // TODO: Handle the fact we might have started writing the response + dReq.jsonErrorResponse(w, util.ErrorResponse(err)) return } - if resErr := r.doDownload(w, cfg, db, activeRemoteRequests, activeThumbnailGeneration); resErr != nil { - r.jsonErrorResponse(w, *resErr) + if metadata == nil { + dReq.jsonErrorResponse(w, util.JSONResponse{ + Code: 404, + JSON: jsonerror.NotFound("File not found"), + }) return } + } func (r *downloadRequest) jsonErrorResponse(w http.ResponseWriter, res util.JSONResponse) { @@ -167,26 +189,27 @@ func (r *downloadRequest) Validate() *util.JSONResponse { return nil } -func (r *downloadRequest) doDownload(w http.ResponseWriter, cfg *config.Dendrite, db *storage.Database, activeRemoteRequests *types.ActiveRemoteRequests, activeThumbnailGeneration *types.ActiveThumbnailGeneration) *util.JSONResponse { +func (r *downloadRequest) doDownload( + w http.ResponseWriter, + cfg *config.Dendrite, + db *storage.Database, + activeRemoteRequests *types.ActiveRemoteRequests, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, +) (*types.MediaMetadata, error) { // check if we have a record of the media in our database mediaMetadata, err := db.GetMediaMetadata(r.MediaMetadata.MediaID, r.MediaMetadata.Origin) if err != nil { - r.Logger.WithError(err).Error("Error querying the database.") - resErr := jsonerror.InternalServerError() - return &resErr + return nil, errors.Wrap(err, "error querying the database") } if mediaMetadata == nil { if r.MediaMetadata.Origin == cfg.Matrix.ServerName { // If we do not have a record and the origin is local, the file is not found - return &util.JSONResponse{ - Code: 404, - JSON: jsonerror.NotFound(fmt.Sprintf("File with media ID %q does not exist", r.MediaMetadata.MediaID)), - } + return nil, nil } // If we do not have a record and the origin is remote, we need to fetch it and respond with that file resErr := r.getRemoteFile(cfg, db, activeRemoteRequests, activeThumbnailGeneration) if resErr != nil { - return resErr + return nil, resErr } } else { // If we have a record, we can respond from the local file @@ -196,26 +219,28 @@ func (r *downloadRequest) doDownload(w http.ResponseWriter, cfg *config.Dendrite } // respondFromLocalFile reads a file from local storage and writes it to the http.ResponseWriter -// Returns a util.JSONResponse error in case of error -func (r *downloadRequest) respondFromLocalFile(w http.ResponseWriter, absBasePath config.Path, activeThumbnailGeneration *types.ActiveThumbnailGeneration, maxThumbnailGenerators int, db *storage.Database, dynamicThumbnails bool, thumbnailSizes []config.ThumbnailSize) *util.JSONResponse { +// If no file was found then returns nil, nil +func (r *downloadRequest) respondFromLocalFile( + w http.ResponseWriter, + absBasePath config.Path, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, + maxThumbnailGenerators int, + db *storage.Database, + dynamicThumbnails bool, + thumbnailSizes []config.ThumbnailSize, +) (*types.MediaMetadata, error) { filePath, err := fileutils.GetPathFromBase64Hash(r.MediaMetadata.Base64Hash, absBasePath) if err != nil { - r.Logger.WithError(err).Error("Failed to get file path from metadata") - resErr := jsonerror.InternalServerError() - return &resErr + return nil, errors.Wrap(err, "failed to get file path from metadata") } file, err := os.Open(filePath) defer file.Close() if err != nil { - r.Logger.WithError(err).Error("Failed to open file") - resErr := jsonerror.InternalServerError() - return &resErr + return nil, errors.Wrap(err, "failed to open file") } stat, err := file.Stat() if err != nil { - r.Logger.WithError(err).Error("Failed to stat file") - resErr := jsonerror.InternalServerError() - return &resErr + return nil, errors.Wrap(err, "failed to stat file") } if r.MediaMetadata.FileSizeBytes > 0 && int64(r.MediaMetadata.FileSizeBytes) != stat.Size() { @@ -223,8 +248,7 @@ func (r *downloadRequest) respondFromLocalFile(w http.ResponseWriter, absBasePat "fileSizeDatabase": r.MediaMetadata.FileSizeBytes, "fileSizeDisk": stat.Size(), }).Warn("File size in database and on-disk differ.") - resErr := jsonerror.InternalServerError() - return &resErr + return nil, errors.New("file size in database and on-disk differ") } var responseFile *os.File @@ -235,7 +259,7 @@ func (r *downloadRequest) respondFromLocalFile(w http.ResponseWriter, absBasePat defer thumbFile.Close() } if resErr != nil { - return resErr + return nil, resErr } if thumbFile == nil { r.Logger.WithFields(log.Fields{ @@ -271,37 +295,38 @@ func (r *downloadRequest) respondFromLocalFile(w http.ResponseWriter, absBasePat " object-src 'self';" w.Header().Set("Content-Security-Policy", contentSecurityPolicy) - if bytesResponded, err := io.Copy(w, responseFile); err != nil { - r.Logger.WithError(err).Warn("Failed to copy from cache") - if bytesResponded == 0 { - resErr := jsonerror.InternalServerError() - return &resErr - } - // If we have written any data then we have already responded with 200 OK and all we can do is close the connection - return nil + if _, err := io.Copy(w, responseFile); err != nil { + return nil, errors.Wrap(err, "failed to copy from cache") } - return nil + return responseMetadata, nil } // Note: Thumbnail generation may be ongoing asynchronously. -func (r *downloadRequest) getThumbnailFile(filePath types.Path, activeThumbnailGeneration *types.ActiveThumbnailGeneration, maxThumbnailGenerators int, db *storage.Database, dynamicThumbnails bool, thumbnailSizes []config.ThumbnailSize) (*os.File, *types.ThumbnailMetadata, *util.JSONResponse) { +// If no thumbnail was found then returns nil, nil, nil +func (r *downloadRequest) getThumbnailFile( + filePath types.Path, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, + maxThumbnailGenerators int, + db *storage.Database, + dynamicThumbnails bool, + thumbnailSizes []config.ThumbnailSize, +) (*os.File, *types.ThumbnailMetadata, error) { var thumbnail *types.ThumbnailMetadata - var resErr *util.JSONResponse + var err error if dynamicThumbnails { - thumbnail, resErr = r.generateThumbnail(filePath, r.ThumbnailSize, activeThumbnailGeneration, maxThumbnailGenerators, db) - if resErr != nil { - return nil, nil, resErr + thumbnail, err = r.generateThumbnail(filePath, r.ThumbnailSize, activeThumbnailGeneration, maxThumbnailGenerators, db) + if err != nil { + return nil, nil, err } } // If dynamicThumbnails is true but there are too many thumbnails being actively generated, we can fall back // to trying to use a pre-generated thumbnail if thumbnail == nil { - thumbnails, err := db.GetThumbnails(r.MediaMetadata.MediaID, r.MediaMetadata.Origin) + var thumbnails []*types.ThumbnailMetadata + thumbnails, err = db.GetThumbnails(r.MediaMetadata.MediaID, r.MediaMetadata.Origin) if err != nil { - r.Logger.WithError(err).Error("Error looking up thumbnails") - resErr := jsonerror.InternalServerError() - return nil, nil, &resErr + return nil, nil, errors.Wrap(err, "error looking up thumbnails") } // If we get a thumbnailSize, a pre-generated thumbnail would be best but it is not yet generated. @@ -316,9 +341,9 @@ func (r *downloadRequest) getThumbnailFile(filePath types.Path, activeThumbnailG "Height": thumbnailSize.Height, "ResizeMethod": thumbnailSize.ResizeMethod, }).Info("Pre-generating thumbnail for immediate response.") - thumbnail, resErr = r.generateThumbnail(filePath, *thumbnailSize, activeThumbnailGeneration, maxThumbnailGenerators, db) - if resErr != nil { - return nil, nil, resErr + thumbnail, err = r.generateThumbnail(filePath, *thumbnailSize, activeThumbnailGeneration, maxThumbnailGenerators, db) + if err != nil { + return nil, nil, err } } } @@ -335,35 +360,36 @@ func (r *downloadRequest) getThumbnailFile(filePath types.Path, activeThumbnailG thumbPath := string(thumbnailer.GetThumbnailPath(types.Path(filePath), thumbnail.ThumbnailSize)) thumbFile, err := os.Open(string(thumbPath)) if err != nil { - r.Logger.WithError(err).Warn("Failed to open file") - resErr := jsonerror.InternalServerError() - return thumbFile, nil, &resErr + thumbFile.Close() + return nil, nil, errors.Wrap(err, "failed to open file") } thumbStat, err := thumbFile.Stat() if err != nil { - r.Logger.WithError(err).Warn("Failed to stat file") - resErr := jsonerror.InternalServerError() - return thumbFile, nil, &resErr + thumbFile.Close() + return nil, nil, errors.Wrap(err, "failed to stat file") } if types.FileSizeBytes(thumbStat.Size()) != thumbnail.MediaMetadata.FileSizeBytes { - r.Logger.WithError(err).Warn("Thumbnail file sizes on disk and in database differ") - resErr := jsonerror.InternalServerError() - return thumbFile, nil, &resErr + thumbFile.Close() + return nil, nil, errors.New("thumbnail file sizes on disk and in database differ") } return thumbFile, thumbnail, nil } -func (r *downloadRequest) generateThumbnail(filePath types.Path, thumbnailSize types.ThumbnailSize, activeThumbnailGeneration *types.ActiveThumbnailGeneration, maxThumbnailGenerators int, db *storage.Database) (*types.ThumbnailMetadata, *util.JSONResponse) { - logger := r.Logger.WithFields(log.Fields{ +func (r *downloadRequest) generateThumbnail( + filePath types.Path, + thumbnailSize types.ThumbnailSize, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, + maxThumbnailGenerators int, + db *storage.Database, +) (*types.ThumbnailMetadata, error) { + r.Logger.WithFields(log.Fields{ "Width": thumbnailSize.Width, "Height": thumbnailSize.Height, "ResizeMethod": thumbnailSize.ResizeMethod, }) busy, err := thumbnailer.GenerateThumbnail(filePath, thumbnailSize, r.MediaMetadata, activeThumbnailGeneration, maxThumbnailGenerators, db, r.Logger) if err != nil { - logger.WithError(err).Error("Error creating thumbnail") - resErr := jsonerror.InternalServerError() - return nil, &resErr + return nil, errors.Wrap(err, "error creating thumbnail") } if busy { return nil, nil @@ -371,9 +397,7 @@ func (r *downloadRequest) generateThumbnail(filePath types.Path, thumbnailSize t var thumbnail *types.ThumbnailMetadata thumbnail, err = db.GetThumbnail(r.MediaMetadata.MediaID, r.MediaMetadata.Origin, thumbnailSize.Width, thumbnailSize.Height, thumbnailSize.ResizeMethod) if err != nil { - logger.WithError(err).Error("Error looking up thumbnails") - resErr := jsonerror.InternalServerError() - return nil, &resErr + return nil, errors.Wrap(err, "error looking up thumbnail") } return thumbnail, nil } @@ -382,8 +406,12 @@ func (r *downloadRequest) generateThumbnail(filePath types.Path, thumbnailSize t // A hash map of active remote requests to a struct containing a sync.Cond is used to only download remote files once, // regardless of how many download requests are received. // Note: The named errorResponse return variable is used in a deferred broadcast of the metadata and error response to waiting goroutines. -// Returns a util.JSONResponse error in case of error -func (r *downloadRequest) getRemoteFile(cfg *config.Dendrite, db *storage.Database, activeRemoteRequests *types.ActiveRemoteRequests, activeThumbnailGeneration *types.ActiveThumbnailGeneration) (errorResponse *util.JSONResponse) { +func (r *downloadRequest) getRemoteFile( + cfg *config.Dendrite, + db *storage.Database, + activeRemoteRequests *types.ActiveRemoteRequests, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, +) (errorResponse error) { // Note: getMediaMetadataFromActiveRequest uses mutexes and conditions from activeRemoteRequests mediaMetadata, resErr := r.getMediaMetadataFromActiveRequest(activeRemoteRequests) if resErr != nil { @@ -397,8 +425,7 @@ func (r *downloadRequest) getRemoteFile(cfg *config.Dendrite, db *storage.Databa defer func() { // Note: errorResponse is the named return variable so we wrap this in a closure to re-evaluate the arguments at defer-time if err := recover(); err != nil { - resErr := jsonerror.InternalServerError() - r.broadcastMediaMetadata(activeRemoteRequests, &resErr) + r.broadcastMediaMetadata(activeRemoteRequests, errors.New("paniced")) panic(err) } r.broadcastMediaMetadata(activeRemoteRequests, errorResponse) @@ -407,26 +434,24 @@ func (r *downloadRequest) getRemoteFile(cfg *config.Dendrite, db *storage.Databa // check if we have a record of the media in our database mediaMetadata, err := db.GetMediaMetadata(r.MediaMetadata.MediaID, r.MediaMetadata.Origin) if err != nil { - r.Logger.WithError(err).Error("Error querying the database.") - resErr := jsonerror.InternalServerError() - return &resErr + return errors.Wrap(err, "error querying the database.") } if mediaMetadata == nil { // If we do not have a record, we need to fetch the remote file first and then respond from the local file - resErr := r.fetchRemoteFileAndStoreMetadata(cfg.Media.AbsBasePath, *cfg.Media.MaxFileSizeBytes, db, cfg.Media.ThumbnailSizes, activeThumbnailGeneration, cfg.Media.MaxThumbnailGenerators) - if resErr != nil { - return resErr + err := r.fetchRemoteFileAndStoreMetadata(cfg.Media.AbsBasePath, *cfg.Media.MaxFileSizeBytes, db, cfg.Media.ThumbnailSizes, activeThumbnailGeneration, cfg.Media.MaxThumbnailGenerators) + if err != nil { + return errors.Wrap(err, "error querying the database.") } } else { // If we have a record, we can respond from the local file r.MediaMetadata = mediaMetadata } } - return + return nil } -func (r *downloadRequest) getMediaMetadataFromActiveRequest(activeRemoteRequests *types.ActiveRemoteRequests) (*types.MediaMetadata, *util.JSONResponse) { +func (r *downloadRequest) getMediaMetadataFromActiveRequest(activeRemoteRequests *types.ActiveRemoteRequests) (*types.MediaMetadata, error) { // Check if there is an active remote request for the file mxcURL := "mxc://" + string(r.MediaMetadata.Origin) + "/" + string(r.MediaMetadata.MediaID) @@ -438,15 +463,12 @@ func (r *downloadRequest) getMediaMetadataFromActiveRequest(activeRemoteRequests // NOTE: Wait unlocks and locks again internally. There is still a deferred Unlock() that will unlock this. activeRemoteRequestResult.Cond.Wait() - if activeRemoteRequestResult.ErrorResponse != nil { - return nil, activeRemoteRequestResult.ErrorResponse + if activeRemoteRequestResult.Error != nil { + return nil, activeRemoteRequestResult.Error } if activeRemoteRequestResult.MediaMetadata == nil { - return nil, &util.JSONResponse{ - Code: 404, - JSON: jsonerror.NotFound("File not found."), - } + return nil, nil } return activeRemoteRequestResult.MediaMetadata, nil @@ -462,24 +484,31 @@ func (r *downloadRequest) getMediaMetadataFromActiveRequest(activeRemoteRequests // broadcastMediaMetadata broadcasts the media metadata and error response to waiting goroutines // Only the owner of the activeRemoteRequestResult for this origin and media ID should call this function. -func (r *downloadRequest) broadcastMediaMetadata(activeRemoteRequests *types.ActiveRemoteRequests, errorResponse *util.JSONResponse) { +func (r *downloadRequest) broadcastMediaMetadata(activeRemoteRequests *types.ActiveRemoteRequests, err error) { activeRemoteRequests.Lock() defer activeRemoteRequests.Unlock() mxcURL := "mxc://" + string(r.MediaMetadata.Origin) + "/" + string(r.MediaMetadata.MediaID) if activeRemoteRequestResult, ok := activeRemoteRequests.MXCToResult[mxcURL]; ok { r.Logger.Info("Signalling other goroutines waiting for this goroutine to fetch the file.") activeRemoteRequestResult.MediaMetadata = r.MediaMetadata - activeRemoteRequestResult.ErrorResponse = errorResponse + activeRemoteRequestResult.Error = err activeRemoteRequestResult.Cond.Broadcast() } delete(activeRemoteRequests.MXCToResult, mxcURL) } // fetchRemoteFileAndStoreMetadata fetches the file from the remote server and stores its metadata in the database -func (r *downloadRequest) fetchRemoteFileAndStoreMetadata(absBasePath config.Path, maxFileSizeBytes config.FileSizeBytes, db *storage.Database, thumbnailSizes []config.ThumbnailSize, activeThumbnailGeneration *types.ActiveThumbnailGeneration, maxThumbnailGenerators int) *util.JSONResponse { - finalPath, duplicate, resErr := r.fetchRemoteFile(absBasePath, maxFileSizeBytes) - if resErr != nil { - return resErr +func (r *downloadRequest) fetchRemoteFileAndStoreMetadata( + absBasePath config.Path, + maxFileSizeBytes config.FileSizeBytes, + db *storage.Database, + thumbnailSizes []config.ThumbnailSize, + activeThumbnailGeneration *types.ActiveThumbnailGeneration, + maxThumbnailGenerators int, +) error { + finalPath, duplicate, err := r.fetchRemoteFile(absBasePath, maxFileSizeBytes) + if err != nil { + return err } r.Logger.WithFields(log.Fields{ @@ -500,8 +529,7 @@ func (r *downloadRequest) fetchRemoteFileAndStoreMetadata(absBasePath config.Pat } // NOTE: It should really not be possible to fail the uniqueness test here so // there is no need to handle that separately - resErr := jsonerror.InternalServerError() - return &resErr + return errors.New("failed to store file metadata in DB") } go func() { @@ -524,13 +552,17 @@ func (r *downloadRequest) fetchRemoteFileAndStoreMetadata(absBasePath config.Pat return nil } -func (r *downloadRequest) fetchRemoteFile(absBasePath config.Path, maxFileSizeBytes config.FileSizeBytes) (types.Path, bool, *util.JSONResponse) { +func (r *downloadRequest) fetchRemoteFile(absBasePath config.Path, maxFileSizeBytes config.FileSizeBytes) (types.Path, bool, error) { r.Logger.Info("Fetching remote file") // create request for remote file - resp, resErr := r.createRemoteRequest() - if resErr != nil { - return "", false, resErr + resp, err := r.createRemoteRequest() + if err != nil { + return "", false, err + } + if resp == nil { + // Remote file not found + return "", false, nil } defer resp.Body.Close() @@ -538,16 +570,11 @@ func (r *downloadRequest) fetchRemoteFile(absBasePath config.Path, maxFileSizeBy contentLength, err := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64) if err != nil { r.Logger.WithError(err).Warn("Failed to parse content length") - return "", false, &util.JSONResponse{ - Code: 502, - JSON: jsonerror.Unknown("Invalid response from remote server"), - } + return "", false, errors.Wrap(err, "invalid response from remote server") } if contentLength > int64(maxFileSizeBytes) { - return "", false, &util.JSONResponse{ - Code: 413, - JSON: jsonerror.Unknown(fmt.Sprintf("Remote file is too large (%v > %v bytes)", contentLength, maxFileSizeBytes)), - } + // TODO: Bubble up this as a 413 + return "", false, fmt.Errorf("remote file is too large (%v > %v bytes)", contentLength, maxFileSizeBytes) } r.MediaMetadata.FileSizeBytes = types.FileSizeBytes(contentLength) r.MediaMetadata.ContentType = types.ContentType(resp.Header.Get("Content-Type")) @@ -568,10 +595,7 @@ func (r *downloadRequest) fetchRemoteFile(absBasePath config.Path, maxFileSizeBy "MaxFileSizeBytes": maxFileSizeBytes, }).Warn("Error while downloading file from remote server") fileutils.RemoveDir(tmpDir, r.Logger) - return "", false, &util.JSONResponse{ - Code: 502, - JSON: jsonerror.Unknown("File could not be downloaded from remote server"), - } + return "", false, errors.New("file could not be downloaded from remote server") } r.Logger.Info("Remote file transferred") @@ -585,9 +609,7 @@ func (r *downloadRequest) fetchRemoteFile(absBasePath config.Path, maxFileSizeBy // The database is the source of truth so we need to have moved the file first finalPath, duplicate, err := fileutils.MoveFileWithHashCheck(tmpDir, r.MediaMetadata, absBasePath, r.Logger) if err != nil { - r.Logger.WithError(err).Error("Failed to move file.") - resErr := jsonerror.InternalServerError() - return "", false, &resErr + return "", false, errors.Wrap(err, "failed to move file") } if duplicate { r.Logger.WithField("dst", finalPath).Info("File was stored previously - discarding duplicate") @@ -597,32 +619,22 @@ func (r *downloadRequest) fetchRemoteFile(absBasePath config.Path, maxFileSizeBy return types.Path(finalPath), duplicate, nil } -func (r *downloadRequest) createRemoteRequest() (*http.Response, *util.JSONResponse) { +func (r *downloadRequest) createRemoteRequest() (*http.Response, error) { matrixClient := gomatrixserverlib.NewClient() resp, err := matrixClient.CreateMediaDownloadRequest(r.MediaMetadata.Origin, string(r.MediaMetadata.MediaID)) if err != nil { - r.Logger.WithError(err).Error("Failed to create download request") - return nil, &util.JSONResponse{ - Code: 502, - JSON: jsonerror.Unknown(fmt.Sprintf("File with media ID %q could not be downloaded from %q", r.MediaMetadata.MediaID, r.MediaMetadata.Origin)), - } + return nil, fmt.Errorf("file with media ID %q could not be downloaded from %q", r.MediaMetadata.MediaID, r.MediaMetadata.Origin) } if resp.StatusCode != 200 { if resp.StatusCode == 404 { - return nil, &util.JSONResponse{ - Code: 404, - JSON: jsonerror.NotFound(fmt.Sprintf("File with media ID %q does not exist", r.MediaMetadata.MediaID)), - } + return nil, nil } r.Logger.WithFields(log.Fields{ "StatusCode": resp.StatusCode, }).Warn("Received error response") - return nil, &util.JSONResponse{ - Code: 502, - JSON: jsonerror.Unknown(fmt.Sprintf("File with media ID %q could not be downloaded from %q", r.MediaMetadata.MediaID, r.MediaMetadata.Origin)), - } + return nil, fmt.Errorf("file with media ID %q could not be downloaded from %q", r.MediaMetadata.MediaID, r.MediaMetadata.Origin) } return resp, nil |