reqwest segmentation fault from AWS Lambda with Rust

1.1k views Asked by At

I can't figure out how to make a simple HTTP request from AWS Lambda using rust without getting a segmentation fault. I get this error regardless of whether I use tokio-0.2 or tokio-0.3 with a compatibility layer. It looks like lambda_http was compiled with tokio-0.2 so it should work.

Cargo.toml:

[package]
name = "req"
version = "0.1.0"
authors = ["X"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lambda_http = { version = "0.2.0-beta.1", git = "https://github.com/awslabs/aws-lambda-rust-runtime" }
tokio = { version = "0.3.4", features = ["full"] }
tokio-compat-02 = "0.1.2"
reqwest = { version = "0.10.9", features = ["json"] }

main.rs

use lambda_http::{
    handler,
    lambda::{self, Context},
    IntoResponse, Request,
};
// NOTE:
// when using tokio-0.2 alone, you get a segmentation fault
// when tokio-0.2 compatibility is enabled with tokio-0.3, you get a segmentation fault
// when tokio-0.2 compatibility is not enabled with tokio-0.3, 'main' panics because 'there is
// no reactor running, must be called from the context of Tokio runtime'
// use tokio_compat_02::FutureExt;

pub type Error = Box<dyn std::error::Error + Send + Sync + 'static>;

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda::run(handler(func)).await?;
    // NOTE: [tokio-0.2 compat] - this doesn't help
    // lambda::run(handler(func)).compat().await?;
    Ok(())
}

async fn func(_: Request, _: Context) -> Result<impl IntoResponse, Error> {
    let _res = reqwest::get("https://www.google.com").await?;
    // NOTE: [tokio-0.2 compat] - this doesn't help
    // let _res = reqwest::get("https://www.google.com").compat().await?;
    Ok("success")
}

deploy.sh:

PKG_CONFIG_ALLOW_CROSS=1 cargo build --release --target x86_64-unknown-linux-musl
cp target/x86_64-unknown-linux-musl/release/req target/x86_64-unknown-linux-musl/release/bootstrap
zip -j target/x86_64-unknown-linux-musl/release/bootstrap.zip target/x86_64-unknown-linux-musl/release/bootstrap
# aws lambda create-function \
#   --function-name reqwest-test \
#   --handler doesnt.matter \
#   --zip-file fileb://target/x86_64-unknown-linux-musl/release/bootstrap.zip \
#   --runtime provided \
#   --role [REMOVED] \
#   --environment Variables={RUST_BACKTRACE=1} \
#   --tracing-config Mode=Active
aws lambda update-function-code \
  --function-name reqwest-test \
  --zip-file fileb://target/x86_64-unknown-linux-musl/release/bootstrap.zip

event.json

{
  "headers": {
    "accept": "*/*",
    "content-length": "0",
    "host": "xxx.execute-api.us-east-1.amazonaws.com",
    "user-agent": "curl/7.64.1",
    "x-amzn-trace-id": "Root=1-5eb33c07-de25b420912dee103a5db434",
    "x-forwarded-for": "65.78.31.245",
    "x-forwarded-port": "443",
    "x-forwarded-proto": "https"
  },
  "isBase64Encoded": false,
  "rawPath": "/",
  "rawQueryString": "",
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "xxx",
    "domainName": "xxx.execute-api.us-east-1.amazonaws.com",
    "domainPrefix": "xxx",
    "http": {
      "method": "GET",
      "path": "/",
      "protocol": "HTTP/1.1",
      "sourceIp": "65.78.31.245",
      "userAgent": "curl/7.64.1"
    },
    "requestId": "MIZRNhJtIAMEMDw=",
    "routeKey": "$default",
    "stage": "$default",
    "time": "06/May/2020:22:36:55 +0000",
    "timeEpoch": 1588804615616
  },
  "routeKey": "$default",
  "version": "2.0"
}
1

There are 1 answers

2
Dan Jenson On

This is solved by not cross-compiling with openssl, which is dynamically linked in glibc. You can change this to reqwest = { version = "0.45.0", default-features = false, features = ["rustls-tls"] }. And if you are using rusoto crates, the same thing except features = ["rustls"].