# Raw Files over HTTP

> Store and serve any file at any path over plain HTTP with curl: CloudRepo has no Raw repository type, so you use a Maven repository, a repository token, PUT, GET and HEAD.

CloudRepo has no Raw repository type. The create form shows an **HTTP** tile that is disabled and marked *Coming soon*, so you cannot create a repository of that type. To store and serve any file over plain HTTP, use a **Maven repository**: it stores a file at any path you name and returns it from the same path. Nothing about the file has to look like a Maven artifact.

This page uses `curl`, so it works from any shell, script or CI job.

## Before you start

- A Maven repository. If you have none, see [Create Your First Repository](/docs/get-started/first-repository.html) and choose **Maven**.
- A repository token with **Read + write** access to it, from [Repository Tokens: Create One and Authenticate](/docs/authenticate/repository-tokens.html). The username is the email address of the account that created the token, and the password is the token.
- `curl` reads that credential from `~/.netrc`, so it never appears on a command line. Create the file, keep it readable by you alone (`chmod 600 ~/.netrc`), and put your organization’s host in it:

`~/.netrc`

```ini
machine your-org.mycloudrepo.io
login you@example.com
password YOUR_REPOSITORY_TOKEN
```

A file’s address is the repository URL plus the path you choose: `https://your-org.mycloudrepo.io/repositories/your-repo/` followed by the path, with no leading slash.

## Upload a file

Make a file to send:

**Terminal**

```bash
echo 'Hello from CloudRepo.' > hello.txt
```

Send it with `--upload-file`, which sends a `PUT` of the file exactly as it is:

**Terminal**

```bash
curl --netrc --fail --upload-file hello.txt \
  https://your-org.mycloudrepo.io/repositories/your-repo/uploads/hello.txt
```

Expected: `curl` exits 0. CloudRepo answers `200` with no body.

Do not send a file with `--data`: curl sends a `POST` unless told otherwise, and a repository URL accepts only `GET`, `HEAD` and `PUT`. It also removes newlines from the file it reads.

## Download a file

**Terminal**

```bash
curl --netrc --fail --output hello-copy.txt \
  https://your-org.mycloudrepo.io/repositories/your-repo/uploads/hello.txt
```

Expected: `hello-copy.txt` holds the bytes you uploaded.

CloudRepo serves every download as `application/octet-stream`, whatever the upload said its type was.

To check that a file exists without downloading it, ask for its headers:

**Terminal**

```bash
curl --netrc --fail --head \
  https://your-org.mycloudrepo.io/repositories/your-repo/uploads/hello.txt
```

Expected: a `200` status line and a `content-length` header. A path nobody stored answers `404 Not Found`.

## List a directory

The portal lists a repository’s files in its file browser. See [Repository Management](/docs/manage/repositories.html#viewing-folders).

The repository also lists a directory over HTTP, as an HTML page with each name, its last modified time and its size. A browser gets it, and so does any client that sends `Accept: text/html` for a path ending in `/`:

**Terminal**

```bash
curl --netrc --fail --header 'Accept: text/html' \
  https://your-org.mycloudrepo.io/repositories/your-repo/uploads/
```

The listing at a repository URL is an HTML page only. A client that asks for a directory path without that header is asking for a file that is not there, and gets `404 Not Found`. The one exception is the repository root, `https://your-org.mycloudrepo.io/repositories/your-repo/`: it answers with the listing, with the header or without. An empty repository answers `404 Not Found`.

## Remove or replace a file

A repository URL has no `DELETE`: it answers `405 Method Not Allowed`. Delete files in the portal. See [Deleting Files and Folders](/docs/manage/repositories.html#deleting-files-and-folders).

A new repository has [Overwrite Protection](/docs/manage/repositories.html#overwrite-protection) on, so a second upload to a path that already holds a file is refused with `409 Conflict`:

**Response**

```text
Version already exists. Overwrites are disabled for this repository.
```

Put each version of a file at its own path (`builds/1.4.0/app.tar.gz`), or turn Overwrite Protection off on a repository that exists to hold replaceable files. With it off, a credential that can write can replace any file in the repository. Two kinds of file can always be replaced: a file whose own directory ends in `-SNAPSHOT` (`builds/1.4.0-SNAPSHOT/app.tar.gz`, but not `builds/1.4.0-SNAPSHOT/logs/app.log`), and `maven-metadata.xml` with its checksum and signature files (`.md5`, `.sha1`, `.sha256`, `.sha512`, `.asc`). See [Maven: SNAPSHOT and Metadata Are Exempt](/docs/manage/repositories.html#maven-snapshot-and-metadata-are-exempt).

## Limits

- **Path.** Use letters, digits and these characters: `+ _ - . ! * ' ( ) / @ ~`. Any other character, such as a space or a percent sign, is refused with `400 Bad Request`. The whole key, `your-org/your-repo/` followed by your path, may be up to 1,024 characters.
- **Size.** One file can be up to 50 GB (50,000,000,000 bytes). A larger file is refused with `413`.

## Serve files without credentials

To let anyone read the files in a repository, turn on its **Public Access** card. See [Enabling Public Repository Access](/docs/manage/repositories.html#enabling-public-repository-access). Reads then work without credentials at `https://your-org.mycloudrepo.io/public/repositories/your-repo/` followed by the path. Writes still need a token.

## When a request is refused

| What you see                  | Why                                                                                                                                                | What to do                                                                                                               |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `401 Unauthorized`            | No credential, or one CloudRepo refused: a mistyped, expired or revoked token, or a username that is not the email address of the token’s account. | Check `~/.netrc` against the token. See [When a publish is refused](/docs/publish/maven.html#when-a-publish-is-refused). |
| `403 Forbidden` on an upload  | The token is **Read only**, or it does not include this repository.                                                                                | Create a **Read + write** token that includes the repository.                                                            |
| `404 Not Found` on a download | Nothing is stored at that path, or the path is a directory.                                                                                        | Check the path. List the directory as shown above.                                                                       |
| `405 Method Not Allowed`      | The request used `DELETE` or `POST`.                                                                                                               | Upload with `--upload-file`. Delete in the portal.                                                                       |
| `409 Conflict` on an upload   | A file is already stored at that path and Overwrite Protection is on.                                                                              | Use a new path, or see above.                                                                                            |
| `400 Bad Request`             | The path holds a character the repository does not accept.                                                                                         | Use only the characters listed under Limits.                                                                             |
| `413` on an upload            | The file is over 50 GB.                                                                                                                            | Split it into several files.                                                                                             |

`curl --fail` shows only a short error that carries the status code, such as `curl: (22) The requested URL returned error: 409`, and hides the body. Add `--fail-with-body` (curl 7.76.0 or later) to see the explanation CloudRepo sends with the refusal.

## Next steps

- [Repository Management](/docs/manage/repositories.html): file browser, Trash, Public Access and Overwrite Protection.
- [Maven Repositories](/docs/formats/maven.html): publish and resolve Maven artifacts from the same repository type.
- [CI/CD overview](/docs/ci/overview.html): hold the token as a CI secret.

---

The page: https://www.cloudrepo.io/docs/formats/raw.html
