0

I am trying to create a REST-API in Rust, using mysqlx and actix_web. I have one database called db in which I have two tables: users and fhekeys. At the moment when a HttpRequest with POST body is received by the API, it retrieves a key from fhekeys in the pk column. But the key is so long, so Rust panicks at the moment of retrieving that variable.

I have already increased max_allow_packet size of mysql in my ubuntu20.04 machine, the thing is that it works fine when I try to "SELECT pk FROM fhekeys" manually in mysql command prompt, but throws the following error when trying to retrieve that value from my Rust program:

thread 'actix-rt|system:0|arbiter:0' panicked at 'cannot advance past `remaining`: 87148184 <= 16777204', /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytes-1.4.0/src/bytes.rs:549:9
stack backtrace:
   0:     0x55a55414a821 - std::backtrace_rs::backtrace::libunwind::trace::h6aeaf83abc038fe6
                               at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
   1:     0x55a55414a821 - std::backtrace_rs::backtrace::trace_unsynchronized::h4f9875212db0ad97
                               at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:     0x55a55414a821 - std::sys_common::backtrace::_print_fmt::h3f820027e9c39d3b
                               at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/sys_c
    ...

I also tried to retrieve some other values from "users", such as "heights" column in the first value, and the function works fine, it retrieves that value correctly as you can see here:

// Function to retrieve the server key from the 'fhekeys' table
async fn get_server_key(pool: &MySqlPool) -> Result<String, sqlx::Error> {
    // Define the SQL query to retrieve the 'pk' key from the 'fhekeys' table
    let query = "SELECT height FROM users";
     // Execute the query and fetch all rows
    let rows: Result<Vec<(String,)>, sqlx::Error> = sqlx::query_as(query).fetch_all(pool).await;

    // Handle the possible outcomes using a match statement
    match rows {
        Ok(rows) => {
            // Extract the 'pk' column values from the rows and concatenate them
            let server_key = rows
                .into_iter()
                .map(|row| row.0)
                .collect::<Vec<String>>()
                .join("");
            // Return the server key
            let server_key_str: String = server_key.chars().take(100).collect();
            println!("Heights : {:?}", server_key_str);
            Ok(server_key)
        }
        Err(err) => Err(err), // Return the error if fetching rows fails
    } 
    
}
// RESULT
✅ Connection to the database is successful!
Heights : "AAAAAAoDAAAAAAAAiiXCvDbtX+qDm8fvf+cmPoXktEyYwh/J6SJjCu0SP7HEEC3deZc8k10PqthJZkE7GHHsp16AY2w2sEHnG4MT"
[2023-08-01T12:31:35Z INFO  actix_web::middleware::logger] 127.0.0.1 "POST /api/healthchecker HTTP/1.1" 200 111 "-" "PostmanRuntime/7.32.3" 0.069827

So the problem comes with fhekeys table, as the only table with a value inside that is so long.

This is the main function for starting the API:

mod routes;
mod fhe;
// mod models;

use actix_cors::Cors;
use actix_web::{HttpServer, web::PayloadConfig, HttpResponse, middleware::Logger, App, http::header};
use sqlx::mysql::{MySqlPool, MySqlPoolOptions};
use dotenv::dotenv;
use routes::{health_route::health_checker_handler, config::config};

pub struct AppState {
    db: MySqlPool,
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    if std::env::var_os("RUST_LOG").is_none() {
        std::env::set_var("RUST_LOG", "actix_web=info");
    }
    dotenv().ok();
    env_logger::init();
    let database_url: String = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = match MySqlPoolOptions::new()
        .max_connections(10)
        .connect(&database_url)
        .await
    {
        Ok(pool) => {
            println!("✅ Connection to the database is successful!");
            pool
        }
        Err(err) => {
            println!(" Failed to connect to the database: {:?}", err);
            std::process::exit(1);
        }
    };

    println!("Server started successfully !");

    HttpServer::new(move || {
        let cors = Cors::default()
            .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
            .allowed_origin("http://localhost:3000")
            .allowed_headers(vec![
                header::CONTENT_TYPE,
                header::AUTHORIZATION,
                header::CONTENT_ENCODING,
                header::ACCEPT,
            ])
            .supports_credentials();

        App::new()
            .app_data(actix_web::web::Data::new(AppState {db: pool.clone()}))
            .service(health_checker_handler)
            .configure(config)
            .wrap(cors)
            .wrap(Logger::default())
            
            
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

And this is the function that retrieves the value from the database:

use actix_web::{post, web, HttpResponse, Responder};
use sqlx::mysql::MySqlPoolOptions;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::mysql::MySqlPool;
use sqlx::query;
use sqlx::mysql::MySqlRow;
use sqlx::{MySql, MySqlConnection};
use crate::AppState; // Make sure to import the AppState struct from main.rs

#[derive(Deserialize, Serialize)]
struct HealthCheckerParams {
   ...
}

#[post("/api/healthchecker")]
pub async fn health_checker_handler(
    query_params: web::Json<HealthCheckerParams>,
    data: web::Data<AppState>
) -> impl Responder {
    
    //Dagtabase url for database queries
    let database_url: String = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    
  ...

    // Retrieve the key from the fhekeys table in the database
    let pool = match MySqlPoolOptions::new()
        .max_connections(10)
        .connect(&database_url)
        .await
            {
                Ok(pool) => {
                    println!("✅ Connection to the database is successful!");
                    pool
                }
                Err(err) => {
                    println!(" Failed to connect to the database: {:?}", err);
                    std::process::exit(1);
                }
            };
    let server_key: String = match get_server_key(&pool)
    .await{
        Ok(key) => key,
        Err(err) => {
            println!("Error retrieving server key: {:?}", err);
            std::process::exit(1);
        }
    };

    // Use the key and other parameters as needed...

    const MESSAGE: &str = "Build Simple Crud";
    HttpResponse::Ok().json(json!({
       ---
    }))
}

// Function to retrieve the server key from the 'fhekeys' table
async fn get_server_key(pool: &MySqlPool) -> Result<String, sqlx::Error> {
    // Define the SQL query to retrieve the 'pk' key from the 'fhekeys' table
    let query = "SELECT pk FROM fhekeys";
     // Execute the query and fetch all rows
    let rows: Result<Vec<(String,)>, sqlx::Error> = sqlx::query_as(query).fetch_all(pool).await;

    // Handle the possible outcomes using a match statement
    match rows {
        Ok(rows) => {
            // Extract the 'pk' column values from the rows and concatenate them
            let server_key = rows
                .into_iter()
                .map(|row| row.0)
                .collect::<Vec<String>>()
                .join("");
            // Return the server key
            let server_key_str: String = server_key.chars().take(100).collect();
            println!("server key : {:?}", server_key_str);
            Ok(server_key)
        }
        Err(err) => Err(err), // Return the error if fetching rows fails
    } 
    
}

Any idea of what that error means? How can I increment the size limit of the HttpResponses in actix web? How can I know if the problem is in the framework actix_web or in a mysqlx query?

cafce25
  • 15,907
  • 4
  • 25
  • 31
Raul
  • 41
  • 4
  • Dang that one is an easy fix if you use Internet Information Services, but whatever equivalent you are using is limiting the throughput somewhere. – easleyfixed Aug 01 '23 at 16:08
  • If its Json you can use this --> https://github.com/actix/actix-web/discussions/2541 But it probably isn't you are doing normal select statements. – easleyfixed Aug 01 '23 at 16:21
  • @easleyfixed can you explain a little bit more? I am a Rust beginner. – Raul Aug 02 '23 at 07:14
  • Well if it was like using Internet Information Services to host the web application there are settings to increase the limits, I have no idea how rust does this. – easleyfixed Aug 02 '23 at 14:52

0 Answers0