Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions crates/crates-io/lib.rs
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#16830 (comment)

Would you mind also updating docs?

I guess we can instead specify content-type in each API respectively

Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ impl Registry {

pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<String> {
let body = serde_json::to_string(&OwnersReq { users: owners })?;
let body = self.put(&format!("/crates/{}/owners", krate), body.as_bytes())?;
let body = self.put(&format!("/crates/{}/owners", krate), Some(body.as_bytes()))?;
assert!(serde_json::from_str::<OwnerResponse>(&body)?.ok);
Ok(serde_json::from_str::<OwnerResponse>(&body)?.msg)
}
Expand Down Expand Up @@ -293,6 +293,7 @@ impl Registry {
self.handle.url(&url)?;
self.handle.in_filesize(size as u64)?;
let mut headers = List::new();
headers.append("Content-Type: application/octet-stream")?;
headers.append("Accept: application/json")?;
headers.append(&format!("Authorization: {}", self.token()?))?;
self.handle.http_headers(headers)?;
Expand Down Expand Up @@ -364,14 +365,14 @@ impl Registry {
}

pub fn unyank(&mut self, krate: &str, version: &str) -> Result<()> {
let body = self.put(&format!("/crates/{}/{}/unyank", krate, version), &[])?;
let body = self.put(&format!("/crates/{}/{}/unyank", krate, version), None)?;
Copy link
Copy Markdown
Contributor Author

@dralley dralley Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was setting Content-Type: application/json for a body which was empty (which is not actually valid json)

assert!(serde_json::from_str::<R>(&body)?.ok);
Ok(())
}

fn put(&mut self, path: &str, b: &[u8]) -> Result<String> {
fn put(&mut self, path: &str, b: Option<&[u8]>) -> Result<String> {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how all of the other methods were written, this was otherwise an outlier.

self.handle.put(true)?;
self.req(path, Some(b), Auth::Authorized)
self.req(path, b, Auth::Authorized)
}

fn get(&mut self, path: &str) -> Result<String> {
Expand Down
35 changes: 29 additions & 6 deletions src/doc/src/reference/registry-web-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,21 @@ be null. The endpoints are versioned with the `v1` component of the path, and
Cargo is responsible for handling backwards compatibility fallbacks should any
be required in the future.

Cargo sets the following headers for all requests:
Cargo sets the `User-Agent` header for all requests to the Cargo version such
as `cargo/1.32.0 (8610973aa 2019-01-02)`. This may be modified by the user in
a configuration value. Added in 1.29.

- `Content-Type`: `application/json` (for requests with a body payload)
- `Accept`: `application/json`
- `User-Agent`: The Cargo version such as `cargo/1.32.0 (8610973aa
2019-01-02)`. This may be modified by the user in a configuration value.
Added in 1.29.
Other headers vary by endpoint and are documented below.

## Publish

- Endpoint: `/api/v1/crates/new`
- Method: PUT
- Authorization: Included
- Headers:
- `Content-Type`: `application/octet-stream`
- `Accept`: `application/json`
- Body: Included (see below)

The publish endpoint is used to publish a new version of a crate. The server
should validate the crate, make it available for download, and add it to the
Expand Down Expand Up @@ -188,6 +190,9 @@ A successful response includes the JSON object:
- Endpoint: `/api/v1/crates/{crate_name}/{version}/yank`
- Method: DELETE
- Authorization: Included
- Headers:
- `Accept`: `application/json`
- Body: None

The yank endpoint will set the `yank` field of the given version of a crate to
`true` in the index.
Expand All @@ -206,6 +211,9 @@ A successful response includes the JSON object:
- Endpoint: `/api/v1/crates/{crate_name}/{version}/unyank`
- Method: PUT
- Authorization: Included
- Headers:
- `Accept`: `application/json`
- Body: None

The unyank endpoint will set the `yank` field of the given version of a crate
to `false` in the index.
Expand All @@ -232,6 +240,9 @@ how [crates.io] handles owners via GitHub users and teams.
- Endpoint: `/api/v1/crates/{crate_name}/owners`
- Method: GET
- Authorization: Included
- Headers:
- `Accept`: `application/json`
- Body: None

The owners endpoint returns a list of owners of the crate.

Expand Down Expand Up @@ -259,6 +270,10 @@ A successful response includes the JSON object:
- Endpoint: `/api/v1/crates/{crate_name}/owners`
- Method: PUT
- Authorization: Included
- Headers:
- `Content-Type`: `application/json`
- `Accept`: `application/json`
- Body: Included (see below)

A PUT request will send a request to the registry to add a new owner to a
crate. It is up to the registry how to handle the request. For example,
Expand Down Expand Up @@ -290,6 +305,10 @@ A successful response includes the JSON object:
- Endpoint: `/api/v1/crates/{crate_name}/owners`
- Method: DELETE
- Authorization: Included
- Headers:
- `Content-Type`: `application/json`
- `Accept`: `application/json`
- Body: Included (see below)

A DELETE request will remove an owner from a crate. The request should include
the following JSON object:
Expand All @@ -316,6 +335,10 @@ A successful response includes the JSON object:

- Endpoint: `/api/v1/crates`
- Method: GET
- Authorization: Not Included
- Headers:
- `Accept`: `application/json`
- Body: None
- Query Parameters:
- `q`: The search query string.
- `per_page`: Number of results, default 10, max 100.
Expand Down