actix-web: actix_web::client cannot use rust-tls for https

I tried to use actix_web::client::Client to send a request to an https url. It works with the “ssl” feature, but not with the “rust-tls” feature.

I condensed it to this sample code:

use actix_rt::System;
use actix_web::client::Client;
use futures::lazy;

fn main() {
    let resp = System::new("test").block_on(lazy(|| {
        Client::default()
            .get("https://www.rust-lang.org")
            .send()
    }));

    println!("Response: {:?}", resp.unwrap());
}

With “ssl” it works and prints the response headers. With “rust-tls” I get Connect(SslIsNotSupported).

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 24 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I was able to successfully call with https in actix_web 4, awc 3.

actix = "0.13.0"
actix-web = "4"
awc = { version = "3.0.0", features = ["openssl"] }
openssl = "0.10.40"

Just got bitten by Err(Connect(SslIsNotSupported)) too 😐. For posterity, and until this makes it to the documentation [1], please try the following (a.k.a. “enabling the SSL/TLS feature”).

[1]: I am willing to open a PR to improve this. Where would you like this documented exactly?


In your Cargo.toml:

  • Using rustls:

    [dependencies]
    actix-rt = "1.1.1"
    actix-web = { version = "3.0.0-alpha.2", features=["rustls"] }
    rustls = "0.17.0"
    
  • Using openssl:

    [dependencies]
    actix-rt = "1.1.1"
    actix-web = { version = "3.0.0-alpha.2", features=["openssl"] }
    openssl = "0.10.29"
    

In your main.rs:

use actix_web::client::Client;

#[actix_rt::main]
async fn main() {
    let client = Client::default();

    // Create request builder and send request
    let response = client
        .get("https://www.rust-lang.org") // <--- notice the "s" in "https://..."
        .header("User-Agent", "Actix-web")
        .send()
        .await; // <- Send http request

    println!("Response: {:?}", response);
}

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.12s
     Running `target/debug/rust-http-playground`
Response: Ok(
ClientResponse HTTP/2.0 200 OK
  headers:
    "strict-transport-security": "max-age=63072000"
    "x-amz-cf-id": "6gculLlBr5lYOjyFkFEErQpKKSY7w2xC70IvsL3ytGEk5HJoJMEMlQ=="
    "x-cache": "Miss from cloudfront"
    "x-xss-protection": "1; mode=block"
    "x-content-type-options": "nosniff"
    "via": "1.1 vegur, 1.1 77ffb7fa0ceed0e909a8f69baef40302.cloudfront.net (CloudFront)"
    "x-amz-cf-pop": "NRT20-C4"
    "content-security-policy": "default-src 'self'; frame-ancestors 'self'; img-src 'self' avatars.githubusercontent.com; frame-src 'self' player.vimeo.com"
    "content-length": "19220"
    "referrer-policy": "no-referrer, strict-origin-when-cross-origin"
    "vary": "Accept-Encoding"
    "server": "Rocket"
    "content-type": "text/html; charset=utf-8"
    "date": "Fri, 15 May 2020 07:32:08 GMT"
)

Somebody please share example how to do it with actix_web 3

Is there a rustls example? I am getting connection timeout with rustls. Openssl is just impossible to compile in windows 10. Tried it for a day.

Sorry, I didn’t get what do you mean. I need to configure something to make it work?

@Pzixel I was able to configure https requests by following awc_https example.

// src/main.rs

use actix_web::client::{Client, Connector};
use openssl::ssl::{SslConnector, SslMethod};

#[actix_rt::main]
async fn main() {
    let builder = SslConnector::builder(SslMethod::tls()).unwrap();

    let client = Client::build()
        .connector(Connector::new().ssl(builder.build()).finish())
        .finish();

    // Create request builder and send request
    let response = client
        .get("https://www.rust-lang.org") // <--- notice the "s" in "https://..."
        .header("User-Agent", "Actix-web")
        .send()
        .await; // <- Send http request

    println!("Response: {:?}", response);
}

Which returns

ClientResponse HTTP/1.1 200 OK
  headers:
    "strict-transport-security": "max-age=63072000"
    "x-amz-cf-id": "nQUn97FTnU4iEG8giZxGeePvVyqrzp8jYsPspK2OvhrtFEMLIrdYiw=="
    "x-cache": "Miss from cloudfront"
    "x-xss-protection": "1; mode=block"
    "x-content-type-options": "nosniff"
    "via": "1.1 vegur, 1.1 650962b00c259fe47c193b15b2fe4b88.cloudfront.net (CloudFront)"
    "x-amz-cf-pop": "VIE50-C1"
    "content-security-policy": "default-src 'self'; frame-ancestors 'self'; img-src 'self' avatars.githubusercontent.com; frame-src 'self' player.vimeo.com"
    "content-length": "19220"
    "referrer-policy": "no-referrer, strict-origin-when-cross-origin"
    "vary": "Accept-Encoding"
    "server": "Rocket"
    "content-type": "text/html; charset=utf-8"
    "date": "Tue, 02 Jun 2020 10:51:59 GMT"
    "connection": "keep-alive"
)

Sorry, I didn’t get what do you mean. I need to configure something to make it work?

@Pzixel I was able to configure https requests by following awc_https example.

// src/main.rs

use actix_web::client::{Client, Connector};
use openssl::ssl::{SslConnector, SslMethod};

#[actix_rt::main]
async fn main() {
    let builder = SslConnector::builder(SslMethod::tls()).unwrap();

    let client = Client::build()
        .connector(Connector::new().ssl(builder.build()).finish())
        .finish();

    // Create request builder and send request
    let response = client
        .get("https://www.rust-lang.org") // <--- notice the "s" in "https://..."
        .header("User-Agent", "Actix-web")
        .send()
        .await; // <- Send http request

    println!("Response: {:?}", response);
}

Which returns

ClientResponse HTTP/1.1 200 OK
  headers:
    "strict-transport-security": "max-age=63072000"
    "x-amz-cf-id": "nQUn97FTnU4iEG8giZxGeePvVyqrzp8jYsPspK2OvhrtFEMLIrdYiw=="
    "x-cache": "Miss from cloudfront"
    "x-xss-protection": "1; mode=block"
    "x-content-type-options": "nosniff"
    "via": "1.1 vegur, 1.1 650962b00c259fe47c193b15b2fe4b88.cloudfront.net (CloudFront)"
    "x-amz-cf-pop": "VIE50-C1"
    "content-security-policy": "default-src 'self'; frame-ancestors 'self'; img-src 'self' avatars.githubusercontent.com; frame-src 'self' player.vimeo.com"
    "content-length": "19220"
    "referrer-policy": "no-referrer, strict-origin-when-cross-origin"
    "vary": "Accept-Encoding"
    "server": "Rocket"
    "content-type": "text/html; charset=utf-8"
    "date": "Tue, 02 Jun 2020 10:51:59 GMT"
    "connection": "keep-alive"
)

This is strange, but example never work on my machine, i always get something like:

Response on post: Err(
    Connect(
        Io(
            Custom {
                kind: Other,
                error: "the handshake failed: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed:ssl\\statem\\statem_clnt.c:1915:: unable to get local issuer certificate",
            },
        ),
    ),
)

The only way to make it work is to disable verification completely (which is not a case to work with)

async fn index(_req: HttpRequest) -> HttpResponse {
    let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
    builder.set_verify(SslVerifyMode::NONE);

    let client = Client::build()
        .connector(Connector::new().ssl(builder.build()).finish())
        .finish();

    let now = std::time::Instant::now();
    let payload =
        client
        .get("https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg")
        .send()
        .await
        .unwrap()
        .body()
        .limit(20_000_000)  // sets max allowable payload size
        .await
        .unwrap();

Can anybody verify this example works out of the box on his machine? (https://github.com/actix/examples/blob/22c8eaae87775d3da53ea3a73067c1a228a3a3a4/awc_https/src/main.rs#L8-L12)

Also my “rustup show”:

stable-x86_64-pc-windows-gnu (default)
rustc 1.43.1 (8d69840ab 2020-05-04)

I using windows 10 x64

Cool, I will try removing reqwest from my project then. Thanks. BRB with results (although not immediately, I need to switch to the task some moment later)