(w http.ResponseWriter, r *http.Request)
| 259 | } |
| 260 | |
| 261 | func (a *APIController) DownloadFileObject(w http.ResponseWriter, r *http.Request) { |
| 262 | ctx := r.Context() |
| 263 | |
| 264 | vars := mux.Vars(r) |
| 265 | objectID, err := getObjectIDFromVars(vars) |
| 266 | if err != nil { |
| 267 | slog.ErrorContext(ctx, "failed to get object ID", "error", err) |
| 268 | handleError(ctx, w, gErrors.NewBadRequestError("invalid objectID: %s", err)) |
| 269 | return |
| 270 | } |
| 271 | |
| 272 | objectDetails, err := a.r.GetFileObject(ctx, objectID) |
| 273 | if err != nil { |
| 274 | handleError(ctx, w, err) |
| 275 | return |
| 276 | } |
| 277 | |
| 278 | w.Header().Set("Content-Type", objectDetails.FileType) |
| 279 | w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", objectDetails.Name)) |
| 280 | w.Header().Set("Content-Length", strconv.FormatInt(objectDetails.Size, 10)) |
| 281 | |
| 282 | if r.Method == http.MethodHead { |
| 283 | return |
| 284 | } |
| 285 | |
| 286 | objectHandle, err := a.r.GetFileObjectReader(ctx, objectID) |
| 287 | if err != nil { |
| 288 | slog.ErrorContext(ctx, "failed to get file object reader", "error", err) |
| 289 | handleError(ctx, w, err) |
| 290 | return |
| 291 | } |
| 292 | defer objectHandle.Close() |
| 293 | copied, err := io.Copy(w, objectHandle) |
| 294 | if err != nil { |
| 295 | slog.ErrorContext(ctx, "failed to stream data", "error", err) |
| 296 | } |
| 297 | if copied < objectDetails.Size { |
| 298 | slog.WarnContext(ctx, "some data was not streamed", "object_id", objectDetails.ID, "object_size", objectDetails.Size, "streamed_bytes", copied) |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | func parseTagsArg(tags string) []string { |
| 303 | var parsedTags []string |
nothing calls this directly
no test coverage detected