{"id":13484828,"url":"https://github.com/algesten/ureq","last_synced_at":"2025-05-14T22:06:07.535Z","repository":{"id":38311003,"uuid":"136835450","full_name":"algesten/ureq","owner":"algesten","description":"A simple, safe HTTP client","archived":false,"fork":false,"pushed_at":"2025-05-04T18:41:50.000Z","size":1788,"stargazers_count":1879,"open_issues_count":25,"forks_count":191,"subscribers_count":11,"default_branch":"main","last_synced_at":"2025-05-07T21:57:50.591Z","etag":null,"topics":["http","httpclient","rust","rust-library"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/algesten.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-06-10T18:43:13.000Z","updated_at":"2025-05-05T23:14:20.000Z","dependencies_parsed_at":"2023-12-09T06:25:56.166Z","dependency_job_id":"e8501a55-16e7-4ef3-b394-c4e9aa6a0ffe","html_url":"https://github.com/algesten/ureq","commit_stats":{"total_commits":1031,"total_committers":100,"mean_commits":10.31,"dds":0.4170708050436469,"last_synced_commit":"de4f0fb8bf5b666d20e420b7ae35a6f31c800544"},"previous_names":[],"tags_count":57,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fureq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fureq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fureq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/algesten%2Fureq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/algesten","download_url":"https://codeload.github.com/algesten/ureq/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254076851,"owners_count":22010611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","httpclient","rust","rust-library"],"created_at":"2024-07-31T17:01:35.301Z","updated_at":"2025-05-14T22:06:07.471Z","avatar_url":"https://github.com/algesten.png","language":"Rust","readme":"[comment]: # (README.md is autogenerated from src/lib.rs by `cargo readme \u003e README.md`)\n\n# ureq\n\n\u003cdiv align=\"center\"\u003e\n \u003c!-- Version --\u003e\n \u003ca href=\"https://crates.io/crates/ureq\"\u003e\n   \u003cimg src=\"https://img.shields.io/crates/v/ureq.svg?style=flat-square\"\n   alt=\"Crates.io version\" /\u003e\n \u003c/a\u003e\n \u003c!-- Docs --\u003e\n \u003ca href=\"https://docs.rs/ureq\"\u003e\n   \u003cimg src=\"https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square\"\n     alt=\"docs.rs docs\" /\u003e\n \u003c/a\u003e\n \u003c!-- Downloads --\u003e\n \u003ca href=\"https://crates.io/crates/ureq\"\u003e\n   \u003cimg src=\"https://img.shields.io/crates/d/ureq.svg?style=flat-square\"\n     alt=\"Crates.io downloads\" /\u003e\n \u003c/a\u003e\n\u003c/div\u003e\n\nA simple, safe HTTP client.\n\nUreq's first priority is being easy for you to use. It's great for\nanyone who wants a low-overhead HTTP client that just gets the job done. Works\nvery well with HTTP APIs. Its features include cookies, JSON, HTTP proxies,\nHTTPS, charset decoding, and is based on the API of the `http` crate.\n\nUreq is in pure Rust for safety and ease of understanding. It avoids using\n`unsafe` directly. It uses blocking I/O instead of async I/O, because that keeps\nthe API simple and keeps dependencies to a minimum. For TLS, ureq uses\nrustls or native-tls.\n\nSee the [changelog] for details of recent releases.\n\n[changelog]: https://github.com/algesten/ureq/blob/main/CHANGELOG.md\n\n## Usage\n\nIn its simplest form, ureq looks like this:\n\n```rust\nlet body: String = ureq::get(\"http://example.com\")\n    .header(\"Example-Header\", \"header value\")\n    .call()?\n    .body_mut()\n    .read_to_string()?;\n```\n\nFor more involved tasks, you'll want to create an [`Agent`]. An Agent\nholds a connection pool for reuse, and a cookie store if you use the\n**cookies** feature. An Agent can be cheaply cloned due to internal\n[`Arc`] and all clones of an Agent share state among each other. Creating\nan Agent also allows setting options like the TLS configuration.\n\n```rust\nuse ureq::Agent;\nuse std::time::Duration;\n\nlet mut config = Agent::config_builder()\n    .timeout_global(Some(Duration::from_secs(5)))\n    .build();\n\nlet agent: Agent = config.into();\n\nlet body: String = agent.get(\"http://example.com/page\")\n    .call()?\n    .body_mut()\n    .read_to_string()?;\n\n// Reuses the connection from previous request.\nlet response: String = agent.put(\"http://example.com/upload\")\n    .header(\"Authorization\", \"example-token\")\n    .send(\"some body data\")?\n    .body_mut()\n    .read_to_string()?;\n```\n\n### JSON\n\nUreq supports sending and receiving json, if you enable the **json** feature:\n\n```rust\nuse serde::{Serialize, Deserialize};\n\n#[derive(Serialize)]\nstruct MySendBody {\n   thing: String,\n}\n\n#[derive(Deserialize)]\nstruct MyRecvBody {\n   other: String,\n}\n\nlet send_body = MySendBody { thing: \"yo\".to_string() };\n\n// Requires the `json` feature enabled.\nlet recv_body = ureq::post(\"http://example.com/post/ingest\")\n    .header(\"X-My-Header\", \"Secret\")\n    .send_json(\u0026send_body)?\n    .body_mut()\n    .read_json::\u003cMyRecvBody\u003e()?;\n```\n\n### Error handling\n\nureq returns errors via `Result\u003cT, ureq::Error\u003e`. That includes I/O errors,\nprotocol errors. By default, also HTTP status code errors (when the\nserver responded 4xx or 5xx) results in [`Error`].\n\nThis behavior can be turned off via [`http_status_as_error()`]\n\n```rust\nuse ureq::Error;\n\nmatch ureq::get(\"http://mypage.example.com/\").call() {\n    Ok(response) =\u003e { /* it worked */},\n    Err(Error::StatusCode(code)) =\u003e {\n        /* the server returned an unexpected status\n           code (such as 400, 500 etc) */\n    }\n    Err(_) =\u003e { /* some kind of io/transport/etc error */ }\n}\n```\n\n## Features\n\nTo enable a minimal dependency tree, some features are off by default.\nYou can control them when including ureq as a dependency.\n\n`ureq = { version = \"3\", features = [\"socks-proxy\", \"charset\"] }`\n\nThe default enabled features are: **rustls** and **gzip**.\n\n* **rustls** enables the rustls TLS implementation. This is the default for the the crate level\n  convenience calls (`ureq::get` etc). It currently uses `ring` as the TLS provider.\n* **native-tls** enables the native tls backend for TLS. Due to the risk of diamond dependencies\n  accidentally switching on an unwanted TLS implementation, `native-tls` is never picked up as\n  a default or used by the crate level convenience calls (`ureq::get` etc) – it must be configured\n  on the agent\n* **platform-verifier** enables verifying the server certificates using a method native to the\n  platform ureq is executing on. See [rustls-platform-verifier] crate\n* **socks-proxy** enables proxy config using the `socks4://`, `socks4a://`, `socks5://`\n   and `socks://` (equal to `socks5://`) prefix\n* **cookies** enables cookies\n* **gzip** enables requests of gzip-compressed responses and decompresses them\n* **brotli** enables requests brotli-compressed responses and decompresses them\n* **charset** enables interpreting the charset part of the Content-Type header\n   (e.g.  `Content-Type: text/plain; charset=iso-8859-1`). Without this, the\n   library defaults to Rust's built in `utf-8`\n* **json** enables JSON sending and receiving via serde_json\n\n#### Unstable\n\nThese features are unstable and might change in a minor version.\n\n* **rustls-no-provider** Enables rustls, but does not enable any [`CryptoProvider`] such as `ring`.\n  Providers other than the default (currently `ring`) are never picked up from feature flags alone.\n  It must be configured on the agent.\n\n* **vendored** compiles and statically links to a copy of non-Rust vendors (e.g. OpenSSL from `native-tls`)\n\n## TLS (https)\n\n### rustls\n\nBy default, ureq uses [`rustls` crate] with the `ring` cryptographic provider.\nAs of Sep 2024, the `ring` provider has a higher chance of compiling successfully. If the user\ninstalls another process [default provider], that choice is respected.\n\nureq does not guarantee to default to ring indefinitely. `rustls` as a feature flag will always\nwork, but the specific crypto backend might change in a minor version.\n\n```rust\n// This uses rustls\nureq::get(\"https://www.google.com/\").call().unwrap();\n```\n\n#### rustls without ring\n\nureq never changes TLS backend from feature flags alone. It is possible to compile ureq\nwithout ring, but it requires specific feature flags and configuring the [`Agent`].\n\nSince rustls is not semver 1.x, this requires non-semver-guaranteed API. I.e. ureq might\nchange this behavior without a major version bump.\n\nRead more at [`TlsConfigBuilder::unversioned_rustls_crypto_provider`][crate::tls::TlsConfigBuilder::unversioned_rustls_crypto_provider].\n\n### native-tls\n\nAs an alternative, ureq ships with [`native-tls`] as a TLS provider. This must be\nenabled using the **native-tls** feature. Due to the risk of diamond dependencies\naccidentally switching on an unwanted TLS implementation, `native-tls` is never picked\nup as a default or used by the crate level convenience calls (`ureq::get` etc) – it\nmust be configured on the agent.\n\n```rust\nuse ureq::config::Config;\nuse ureq::tls::{TlsConfig, TlsProvider};\n\nlet mut config = Config::builder()\n    .tls_config(\n        TlsConfig::builder()\n            // requires the native-tls feature\n            .provider(TlsProvider::NativeTls)\n            .build()\n    )\n    .build();\n\nlet agent = config.new_agent();\n\nagent.get(\"https://www.google.com/\").call().unwrap();\n```\n\n### Root certificates\n\n#### webpki-roots\n\nBy default, ureq uses Mozilla's root certificates via the [webpki-roots] crate. This is a static\nbundle of root certificates that do not update automatically. It also circumvents whatever root\ncertificates are installed on the host running ureq, which might be a good or a bad thing depending\non your perspective. There is also no mechanism for [SCT], [CRL]s or other revocations.\nTo maintain a \"fresh\" list of root certs, you need to bump the ureq dependency from time to time.\n\nThe main reason for chosing this as the default is to minimize the number of dependencies. More\ndetails about this decision can be found at [PR 818].\n\nIf your use case for ureq is talking to a limited number of servers with high trust, the\ndefault setting is likely sufficient. If you use ureq with a high number of servers, or servers\nyou don't trust, we recommend using the platform verifier (see below).\n\n#### platform-verifier\n\nThe [rustls-platform-verifier] crate provides access to natively checking the certificate via your OS.\nTo use this verifier, you need to enable it using feature flag **platform-verifier** as well as\nconfigure an agent to use it.\n\n```rust\nuse ureq::Agent;\nuse ureq::tls::{TlsConfig, RootCerts};\n\nlet agent = Agent::config_builder()\n    .tls_config(\n        TlsConfig::builder()\n            .root_certs(RootCerts::PlatformVerifier)\n            .build()\n    )\n    .build()\n    .new_agent();\n\nlet response = agent.get(\"https://httpbin.org/get\").call()?;\n```\n\nSetting `RootCerts::PlatformVerifier` together with `TlsProvider::NativeTls` means\nalso native-tls will use the OS roots instead of [webpki-roots] crate. Whether that\nresults in a config that has CRLs and revocations is up to whatever native-tls links to.\n\n## JSON\n\nBy enabling the **json** feature, the library supports serde json.\n\nThis is enabled by default.\n\n* [`request.send_json()`] send body as json.\n* [`body.read_json()`] transform response to json.\n\n## Sending body data\n\nHTTP/1.1 has two ways of transfering body data. Either of a known size with\nthe `Content-Length` HTTP header, or unknown size with the\n`Transfer-Encoding: chunked` header. ureq supports both and will use the\nappropriate method depending on which body is being sent.\n\nureq has a [`AsSendBody`] trait that is implemented for many well known types\nof data that we might want to send. The request body can thus be anything\nfrom a `String` to a `File`, see below.\n\n### Content-Length\n\nThe library will send a `Content-Length` header on requests with bodies of\nknown size, in other words, if the body to send is one of:\n\n* `\u0026[u8]`\n* `\u0026[u8; N]`\n* `\u0026str`\n* `String`\n* `\u0026String`\n* `Vec\u003cu8\u003e`\n* `\u0026Vec\u003cu8\u003e)`\n* [`SendBody::from_json()`] (implicitly via [`request.send_json()`])\n\n### Transfer-Encoding: chunked\n\nureq will send a `Transfer-Encoding: chunked` header on requests where the body\nis of unknown size. The body is automatically converted to an [`std::io::Read`]\nwhen the type is one of:\n\n* `File`\n* `\u0026File`\n* `TcpStream`\n* `\u0026TcpStream`\n* `Stdin`\n* `UnixStream` (not on windows)\n\n#### From readers\n\nThe chunked method also applies for bodies constructed via:\n\n* [`SendBody::from_reader()`]\n* [`SendBody::from_owned_reader()`]\n\n### Proxying a response body\n\nAs a special case, when ureq sends a [`Body`] from a previous http call, the\nuse of `Content-Length` or `chunked` depends on situation. For input such as\ngzip decoding (**gzip** feature) or charset transformation (**charset** feature),\nthe output body might not match the input, which means ureq is forced to use\nthe `chunked` method.\n\n* `Response\u003cBody\u003e`\n\n### Sending form data\n\n[`request.send_form()`] provides a way to send `application/x-www-form-urlencoded`\nencoded data. The key/values provided will be URL encoded.\n\n### Overriding\n\nIf you set your own Content-Length or Transfer-Encoding header before\nsending the body, ureq will respect that header by not overriding it,\nand by encoding the body or not, as indicated by the headers you set.\n\n```rust\nlet resp = ureq::put(\"https://httpbin.org/put\")\n    .header(\"Transfer-Encoding\", \"chunked\")\n    .send(\"Hello world\")?;\n```\n\n## Character encoding\n\nBy enabling the **charset** feature, the library supports receiving other\ncharacter sets than `utf-8`.\n\nFor [`Body::read_to_string()`] we read the header like:\n\n`Content-Type: text/plain; charset=iso-8859-1`\n\nand if it contains a charset specification, we try to decode the body using that\nencoding. In the absence of, or failing to interpret the charset, we fall back on `utf-8`.\n\nCurrently ureq does not provide a way to encode when sending request bodies.\n\n### Lossy utf-8\n\nWhen reading text bodies (with a `Content-Type` starting `text/` as in `text/plain`,\n`text/html`, etc), ureq can ensure the body is possible to read as a `String` also if\nit contains characters that are not valid for utf-8. Invalid characters are replaced\nwith a question mark `?` (NOT the utf-8 replacement character).\n\nFor [`Body::read_to_string()`] this is turned on by default, but it can be disabled\nand conversely for [`Body::as_reader()`] it is not enabled, but can be.\n\nTo precisely configure the behavior use [`Body::with_config()`].\n\n## Proxying\n\nureq supports two kinds of proxies,  [`HTTP`] ([`CONNECT`]), [`SOCKS4`]/[`SOCKS5`],\nthe former is always available while the latter must be enabled using the feature\n**socks-proxy**.\n\nProxies settings are configured on an [`Agent`]. All request sent through the agent will be proxied.\n\n### Example using HTTP\n\n```rust\nuse ureq::{Agent, Proxy};\n// Configure an http connect proxy.\nlet proxy = Proxy::new(\"http://user:password@cool.proxy:9090\")?;\nlet agent: Agent = Agent::config_builder()\n    .proxy(Some(proxy))\n    .build()\n    .into();\n\n// This is proxied.\nlet resp = agent.get(\"http://cool.server\").call()?;\n```\n\n### Example using SOCKS5\n\n```rust\nuse ureq::{Agent, Proxy};\n// Configure a SOCKS proxy.\nlet proxy = Proxy::new(\"socks5://user:password@cool.proxy:9090\")?;\nlet agent: Agent = Agent::config_builder()\n    .proxy(Some(proxy))\n    .build()\n    .into();\n\n// This is proxied.\nlet resp = agent.get(\"http://cool.server\").call()?;\n```\n\n## Log levels\n\nureq uses the log crate. These are the definitions of the log levels, however we\ndo not guarantee anything for dependencies such as `http` and `rustls`.\n\n* `ERROR` - nothing\n* `WARN` - if we detect a user configuration problem.\n* `INFO` - nothing\n* `DEBUG` - uri, state changes, transport, resolver and selected request/response headers\n* `TRACE` - wire level debug. NOT REDACTED!\n\nThe request/response headers on DEBUG levels are allow-listed to only include headers that\nare considered safe. The code has the [allow list](https://github.com/algesten/ureq/blob/81127cfc38516903330dc1b9c618122372f8dc29/src/util.rs#L184-L198).\n\n## Versioning\n\n### Semver and `unversioned`\n\nureq follows semver. From ureq 3.x we strive to have a much closer adherence to semver than 2.x.\nThe main mistake in 2.x was to re-export crates that were not yet semver 1.0. In ureq 3.x TLS and\ncookie configuration is shimmed using our own types.\n\nureq 3.x is trying out two new traits that had no equivalent in 2.x, [`Transport`] and [`Resolver`].\nThese allow the user write their own bespoke transports and (DNS name) resolver. The API:s for\nthese parts are not yet solidified. They live under the [`unversioned`] module, and do not\nfollow semver. See module doc for more info.\n\n### Breaking changes in dependencies\n\nureq relies on non-semver 1.x crates such as `rustls` and `native-tls`. Some scenarios, such\nas configuring `rustls` to not use `ring`, a user of ureq might need to interact with these\ncrates directly instead of going via ureq's provided API.\n\nSuch changes can break when ureq updates dependencies. This is not considered a breaking change\nfor ureq and will not be reflected by a major version bump.\n\nWe strive to mark ureq's API with the word \"unversioned\" to identify places where this risk arises.\n\n### Minimum Supported Rust Version (MSRV)\n\nFrom time to time we will need to update our minimum supported Rust version (MSRV). This is not\nsomething we do lightly; our ambition is to be as conservative with MSRV as possible.\n\n* For some dependencies, we will opt for pinning the version of the dep instead\n  of bumping our MSRV.\n* For important dependencies, like the TLS libraries, we cannot hold back our MSRV if they change.\n* We do not consider MSRV changes to be breaking for the purposes of semver.\n* We will not make MSRV changes in patch releases.\n* MSRV changes will get their own minor release, and not be co-mingled with other changes.\n\n[`HTTP`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling#http_tunneling\n[`CONNECT`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT\n[`SOCKS4`]: https://en.wikipedia.org/wiki/SOCKS#SOCKS4\n[`SOCKS5`]: https://en.wikipedia.org/wiki/SOCKS#SOCKS5\n[`rustls` crate]: https://crates.io/crates/rustls\n[default provider]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html#method.install_default\n[`native-tls`]: https://crates.io/crates/native-tls\n[rustls-platform-verifier]: https://crates.io/crates/rustls-platform-verifier\n[webpki-roots]: https://crates.io/crates/webpki-roots\n[`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html\n[`Agent`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.Agent.html\n[`Error`]: https://docs.rs/ureq/3.0.0-rc4/ureq/enum.Error.html\n[`http_status_as_error()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/config/struct.ConfigBuilder.html#method.http_status_as_error\n[SCT]: https://en.wikipedia.org/wiki/Certificate_Transparency\n[CRL]: https://en.wikipedia.org/wiki/Certificate_revocation_list\n[PR818]: https://github.com/algesten/ureq/pull/818\n[`request.send_json()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.RequestBuilder.html#method.send_json\n[`body.read_json()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.Body.html#method.read_json\n[`AsSendBody`]: https://docs.rs/ureq/3.0.0-rc4/ureq/trait.AsSendBody.html\n[`SendBody::from_json()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.SendBody.html#method.from_json\n[`std::io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html\n[`SendBody::from_reader()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.SendBody.html#method.from_reader\n[`SendBody::from_owned_reader()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.SendBody.html#method.from_owned_reader\n[`Body`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.Body.html\n[`request.send_form()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.RequestBuilder.html#method.send_form\n[`Body::read_to_string()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.Body.html#method.read_to_string\n[`Body::as_reader()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.Body.html#method.as_reader\n[`Body::with_config()`]: https://docs.rs/ureq/3.0.0-rc4/ureq/struct.Body.html#method.with_config\n[`Transport`]: https://docs.rs/ureq/3.0.0-rc4/ureq/unversioned/transport/trait.Transport.html\n[`Resolver`]: https://docs.rs/ureq/3.0.0-rc4/ureq/unversioned/resolver/trait.Resolver.html\n[`unversioned`]: https://docs.rs/ureq/3.0.0-rc4/ureq/unversioned/index.html\n[`CryptoProvider`]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html\n","funding_links":[],"categories":["Rust","Libraries"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falgesten%2Fureq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falgesten%2Fureq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falgesten%2Fureq/lists"}