# File.IsOwnUpload and File.SaveUpload

> A private upload's path records WHO uploaded it — the signed-in account, or the browser's visit when nobody was signed in. `File.IsOwnUpload(path)` answers whether the caller made it, which a function keeping an upload as the caller's file checks first, so a path that leaks cannot be claimed by another session. `File.SaveUpload` stores bytes as a private upload of the caller, exactly as `Upload(privately: true)` does from a page.

<!-- id: storage-own-upload · area: storage · stability: preview · html: https://osysharp.com/reference/storage/own-upload/ -->

## Summary        {#summary}
A private upload — `Upload(privately: true)` on a page, a paste or a drop — lands at a path the platform chooses under
`uploads/`, and that path records who made it. The page then hands the path to one of your functions. Before that
function keeps the file as the caller's own, it asks:

```osy syntax
if (!File.IsOwnUpload(upload.Path)) { throw new ValidationException("Please upload the file again."); }
```

`true` means the caller uploaded it — the same signed-in person, or, signed out, the same browser. Anybody else holding
the path — a log line, a shared screen, another tab signed in as somebody else — gets `false`.

## Signature      {#signature}
```osy syntax
bool   File.IsOwnUpload(string path)                    // did the CALLER upload this private upload?
string File.SaveUpload(string fileName, byte[] bytes)   // store bytes as the caller's private upload; answers its path
```

## Description    {#description}
Needs `use Osysharp.Storage;`.

- **Who "the caller" is.** The signed-in account, or the visit the platform issued the browser when nobody is signed
  in. Both are tried, so somebody who pasted a screenshot signed out and then signed in is still its uploader. Neither
  is an argument: you cannot ask on somebody else's behalf.
- **What answers `false`.** Any path the platform did not choose for a private upload (`public/…`, a path your own code
  wrote with `File.WriteAllBytes`), and any upload made by somebody else.
- **`File.SaveUpload`** keeps the file name's extension and nothing else of it. It is refused when there is nobody to
  record — a background run with no caller writes bytes with `File.WriteAllBytes` instead. In a test it is how a test
  stands in for the page's upload: `runas` the person, save, and hand the path to the function under test.
- **Uploads are limited.** One browser (or one signed-in person) may upload 30 files a minute and 200 MB an hour to an
  app, and one network address 300 files a minute. Past that the upload is refused with `429` and the sentence "Too
  many files have been uploaded from here in a short time. Wait … and try again.", and nothing is stored. These are the
  defaults; whoever runs the platform sets its own numbers under `Platform:Uploads` (`UploadsPerCallerPerMinute`,
  `MegabytesPerCallerPerHour`, `UploadsPerAddressPerMinute`).

## Examples       {#examples}
```osy title="keep an upload as the caller's own file" test app=storage-own-upload
app Desk { use Osysharp.Storage; }

using Osysharp.Storage;

[AllowAnonymous]
public Guid Keep(UploadedFile upload) {
  if (!File.IsOwnUpload(upload.Path)) {
    throw new ValidationException("That file was uploaded somewhere else. Please upload it again.");
  }
  var file = File.Create(upload.FileName, upload.ContentType, File.ReadAllBytes(upload.Path));
  File.Delete(upload.Path);
  return file.Id;
}
```

```osy title="another browser holding the path cannot keep it" run app=storage-own-upload
[Test]
void An_upload_is_its_uploaders() {
  var path = "";
  runas (new Visitor { Id = "visit-a" }) { path = File.SaveUpload("shot.png", [137, 80, 78, 71]); }
  runas (new Visitor { Id = "visit-b" }) { Assert.False(File.IsOwnUpload(path)); }
  runas (new Visitor { Id = "visit-a" }) { Assert.True(File.IsOwnUpload(path)); }
}
```

## See also       {#see-also}
- [upload](https://osysharp.com/reference/ui/upload/) — the `Upload` atom, and `privately: true`
- [Files (addressing something the app stores)](https://osysharp.com/reference/storage/index/) — the two ways the platform stores a file
- [File.SignedUrl](https://osysharp.com/reference/storage/file-signed-url/) — how a private file is shown
