Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
eabd13a
format and special toolchain
fewensa Nov 26, 2021
c9ac3aa
refactor raw builder
fewensa Nov 28, 2021
e2f2ac2
ci
fewensa Nov 28, 2021
601871b
ci
fewensa Nov 28, 2021
40e1d75
ci
fewensa Nov 28, 2021
d70ae3d
ci
fewensa Nov 28, 2021
a626952
ci
fewensa Nov 28, 2021
9c5b96f
danger config
fewensa Nov 28, 2021
20b6a52
clippy
fewensa Nov 28, 2021
78d81a8
lint
fewensa Nov 28, 2021
d5cdfb8
refactor features
fewensa Nov 28, 2021
398a20e
refactor features
fewensa Nov 29, 2021
eefa751
Revert test host
fewensa Apr 17, 2022
99676a0
Migrate async client to futures and socket2 (#2)
fewensa Feb 7, 2026
5496be9
Migrate async client to futures and socket2 (#3)
fewensa Feb 7, 2026
d058619
Migrate to socket2: update features, async TLS handling, config tests…
fewensa Feb 7, 2026
5234308
Restore checkout v6 in CI (#8)
fewensa Feb 7, 2026
1d6f6f0
Fix build errors: socket2 API, rustls trait impl, async field access,…
fewensa Mar 9, 2026
a54f8a3
Fix refactor dependency compatibility (#11)
fewensa Mar 13, 2026
f4e9d2c
chore: clean up clippy warnings and upgrade workspace resolver (#12)
fewensa Mar 14, 2026
9ba4b20
Implement async TLS via futures-rustls (BES-27) (#13)
fewensa Mar 14, 2026
8417df7
feat: implement HTTP auth() with Basic and Bearer support (BES-29) (#14)
fewensa Mar 14, 2026
2caceff
chore: remove empty block_stream.rs placeholder file
fewensa Mar 14, 2026
44411e6
Add local SOCKS proxy coverage (#15)
fewensa Mar 14, 2026
9c3fa88
Align refactor HTTP client behavior
fewensa Mar 14, 2026
49e11aa
Add missing async proxy test attribute (#16)
fewensa Mar 14, 2026
1264efa
Remove dead debug code, update CI branches, bump version to 0.2.0 (#17)
fewensa Mar 14, 2026
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
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable

- name: Cache cargo build
uses: Swatinem/rust-cache@v2

- name: Format
run: cargo fmt --all -- --check

- name: Lint
run: cargo clippy --all -- -D warnings

- name: Run tests
run: cargo test --all-features
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ members = [
"rttp",
"rttp_client",
]
resolver = "2"
17 changes: 8 additions & 9 deletions rttp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rttp"
version = "0.1.0"
version = "0.2.0"
authors = ["fewensa <fewensa@protonmail.com>"]
description = "Rust http lib"
homepage = "https://github.com/fewensa/rttp"
Expand All @@ -15,24 +15,24 @@ include = [
]

readme = "README.md"
edition = "2018"
edition = "2021"

[dependencies]

rttp_client = { version = "=0.1.0", optional = true, path = "../rttp_client", features = [ "tls-native", "async" ] }
rttp_client = { optional = true, path = "../rttp_client", features = [ "tls-native", "async" ] }

[dev-dependencies]


async-std = { version = "1" }


[features]
default = []

all = ["rttp_client"]
client = ["rttp_client"]
#client_tls_native = ["rttp_client"]
#client_tls_rustls = ["rttp_client"]
async = ["client", "rttp_client/async"]
tls-native = ["client", "rttp_client/tls-native"]
tls-rustls = ["client", "rttp_client/tls-rustls"]
all = ["client", "async", "tls-native", "tls-rustls"]


#[target.'cfg(feature = "all")'.dependencies]
Expand All @@ -46,4 +46,3 @@ client = ["rttp_client"]
#
#[target.'cfg(feature = "client_tls_rustls")'.dependencies]
#rttp_client = { version = "=0.1.0", path = "../rttp_client", optional = true, default-features = false, features = [ "tls-rustls" ] }

8 changes: 1 addition & 7 deletions rttp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
pub struct Http {}


impl Http {
#[cfg(any(
feature = "all",
feature = "client",
feature = "client_tls_rustls",
feature = "client_tls_native",
))]
#[cfg(feature = "client")]
pub fn client() -> rttp_client::HttpClient {
rttp_client::HttpClient::new()
}
Expand Down
31 changes: 17 additions & 14 deletions rttp/tests/test_client.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
use rttp::Http;

#[test]
#[cfg(any(feature = "all", feature = "client"))]
fn test_client_http() {
let response = Http::client()
.url("http://httpbin.org/get")
.emit();
let response = rttp::Http::client().url("http://httpbin.org/get").emit();
assert!(response.is_ok());
let response = response.unwrap();
println!("{}", response);
}

#[test]
#[cfg(any(feature = "all", feature = "client", feature = "client_tls_native", feature = "client_tls_rustls"))]
#[cfg(any(
feature = "all",
feature = "client",
feature = "tls-native",
feature = "tls-rustls"
))]
fn test_client_https() {
let response = Http::client()
.url("https://bing.com")
.emit();
let response = rttp::Http::client().url("https://httpbin.org/get").emit();
assert!(response.is_ok());
let response = response.unwrap();
println!("{}", response);
}

#[test]
#[cfg(any(feature = "all", feature = "client"))]
#[cfg(any(feature = "all", feature = "async"))]
fn test_client_async_http() {
async_std::task::block_on(async {
let response = Http::client()
let response = rttp::Http::client()
.post()
.url("http://httpbin.org/post")
.form(("debug", "true", "name=Form&file=@cargo#../Cargo.toml"))
Expand All @@ -40,10 +39,15 @@ fn test_client_async_http() {
}

#[test]
#[cfg(any(feature = "all", feature = "client", feature = "client_tls_native", feature = "client_tls_rustls"))]
#[cfg(any(
feature = "all",
feature = "async",
feature = "tls-native",
feature = "tls-rustls"
))]
fn test_client_async_https() {
async_std::task::block_on(async {
let response = Http::client()
let response = rttp::Http::client()
.post()
.url("https://httpbin.org/get")
.rasync()
Expand All @@ -54,4 +58,3 @@ fn test_client_async_https() {
println!("{}", response);
});
}

55 changes: 38 additions & 17 deletions rttp_client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rttp_client"
version = "0.1.0"
version = "0.2.0"
authors = ["fewensa <fewensa@protonmail.com>"]
description = "Rust http client lib"
homepage = "https://github.com/fewensa/rttp"
Expand All @@ -15,32 +15,53 @@ include = [
]

readme = "README.md"
edition = "2018"
edition = "2021"

[dependencies]
url = "2"
tracing = "0.1"
socket2 = "0.5"
futures = "0.3"

url = "2"
percent-encoding = "2"

mime = "0.3"
mime = "0.3"
mime_guess = "2"

rand = "0.7"
socks = "0.3"
base64 = "0.11"
flate2 = "1.0"
httpdate = "0.3"
rand = "0.8"
socks = "0.3"
base64 = "0.22"
flate2 = "1.0"
httpdate = "1.0"


native-tls = { optional = true, version = "0.2" }
async-native-tls = { optional = true, version = "0.5" }

native-tls = { version = "0.2", optional = true }
rustls = { version = "0.16", optional = true }
webpki-roots = { version = "0.18", optional = true }
webpki = { version = "0.21", optional = true }
rustls = { optional = true, version = "0.23" }
webpki-roots = { optional = true, version = "0.26" }
futures-rustls = { optional = true, version = "0.26" }

async-std = { version = "1", optional = true }

[features]
default = []
async = []
tls-native = ["native-tls", "async-native-tls"]
tls-rustls = ["rustls", "webpki-roots", "futures-rustls"]

##
# warning: /data/rttp/rttp_client/Cargo.toml: Found `feature = ...` in `target.'cfg(...)'.dependencies`.
# This key is not supported for selecting dependencies and will not work as expected.
# Use the [features] section instead: https://doc.rust-lang.org/cargo/reference/features.html
##
#[target.'cfg(any(feature = "async-std", feature = "async-tokio"))'.features]
#tls-native = ["async-native-tls"]
#tls-rustls = ["async-rustls", "webpki", "webpki-roots"]

## Not good way
#[target.'cfg(any(feature = "async-std", feature = "async-tokio"))'.dependencies]
#tls-native = { optional = true, package = "async-native-tls", version = "0.4" }
#tls-rustls = { optional = true, package = "async-rustls", version = "0.2" }

tls-native = ["native-tls"]
tls-rustls = ["rustls", "webpki", "webpki-roots"]
async = ["async-std"]
[dev-dependencies]
rcgen = "0.11"
49 changes: 27 additions & 22 deletions rttp_client/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{Config, error};
#[cfg(feature = "async")]
use crate::connection::AsyncConnection;
use crate::connection::BlockConnection;
use crate::request::{RawRequest, Request};
use crate::response::Response;
use crate::types::{Header, IntoHeader, IntoPara, Proxy, ToFormData, ToRoUrl};
use crate::types::{Auth, Header, IntoHeader, IntoPara, Proxy, ToFormData, ToRoUrl};
use crate::{error, Config};

#[derive(Debug)]
pub struct HttpClient {
Expand All @@ -14,13 +14,12 @@ pub struct HttpClient {
impl Default for HttpClient {
fn default() -> Self {
Self {
request: Request::new()
request: Request::new(),
}
}
}

impl HttpClient {

/// Create a `HttpClient` object.
/// # Examples
/// ```rust
Expand All @@ -32,14 +31,11 @@ impl HttpClient {
}

pub(crate) fn with_request(request: Request) -> Self {
Self {
request
}
Self { request }
}
}

impl HttpClient {

/// Set count of this request auto redirect times.
pub(crate) fn count(&mut self, count: u32) -> &mut Self {
self.request.count_set(count);
Expand Down Expand Up @@ -108,8 +104,7 @@ impl HttpClient {

/// Add url path
pub fn path<S: AsRef<str>>(&mut self, path: S) -> &mut Self {
let mut paths = self.request.paths_mut();
paths.push(path.as_ref().into());
self.request.paths_mut().push(path.as_ref().into());
self
}

Expand All @@ -125,19 +120,31 @@ impl HttpClient {
self
}

/// Not support now
pub fn auth(&mut self) -> &mut Self {
unimplemented!()
/// Set HTTP authentication. Supports Basic Auth and Bearer Token.
///
/// # Examples
///
/// ```rust
/// use rttp_client::HttpClient;
/// use rttp_client::types::Auth;
///
/// let mut client = HttpClient::new();
/// client.auth(Auth::basic("user", "secret"));
/// client.auth(Auth::bearer("my-token"));
/// ```
pub fn auth<A: AsRef<Auth>>(&mut self, auth: A) -> &mut Self {
self.header(("Authorization", auth.as_ref().header_value().as_str()))
}

/// Add request header
/// Add request header
pub fn header<P: IntoHeader>(&mut self, header: P) -> &mut Self {
let mut headers = self.request.headers_mut();
let headers = self.request.headers_mut();
for h in header.into_headers() {
let mut exi = headers.iter_mut()
let exit = headers
.iter_mut()
.find(|d| d.name().eq_ignore_ascii_case(h.name()));

if let Some(eh) = exi {
if let Some(eh) = exit {
if h.name().eq_ignore_ascii_case("cookie") {
let new_cookie_value = format!("{};{}", eh.value(), h.value());
eh.replace(Header::new("Cookie", new_cookie_value));
Expand Down Expand Up @@ -165,16 +172,14 @@ impl HttpClient {
/// Add request para
pub fn para<P: IntoPara>(&mut self, para: P) -> &mut Self {
let paras = para.into_paras();
let mut req_paras = self.request.paras_mut();
req_paras.extend(paras);
self.request.paras_mut().extend(paras);
self
}

/// Add request form data. include file
pub fn form<S: ToFormData>(&mut self, formdata: S) -> &mut Self {
let formdatas = formdata.to_formdatas();
let mut req_formdatas = self.request.formdatas_mut();
req_formdatas.extend(formdatas);
self.request.formdatas_mut().extend(formdatas);
self
}

Expand Down Expand Up @@ -204,7 +209,7 @@ impl HttpClient {
return Err(error::connection_closed());
}
let request = RawRequest::block_new(&mut self.request)?;
BlockConnection::new(request).block_call()
BlockConnection::new(request).call()
}

/// Async request emit
Expand Down
Loading