help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
rust-web-server
/
src
RSK World
rust-web-server
Rust Web Server - High-Performance Async Web Server + WebSocket Support + JWT Authentication + File Upload + Memory Safety + Educational Design
src
  • auth.rs15.7 KB
  • config.rs2.9 KB
  • error.rs5.2 KB
  • file_upload.rs19 KB
  • handlers.rs12.8 KB
  • lib.rs1.8 KB
  • main.rs6 KB
  • middleware.rs6.2 KB
  • static_files.rs9.9 KB
  • utils.rs9.6 KB
  • websocket.rs15.3 KB
utils.rs
src/utils.rs
Raw Download
Find: Go to:
/*
 * Utility Functions Module - Rust Web Server
 * 
 * Created by RSK World (https://rskworld.in)
 * Founder: Molla Samser
 * Designer & Tester: Rima Khatun
 * 
 * Contact:
 * - Email: hello@rskworld.in, support@rskworld.in
 * - Phone: +91 93305 39277
 * - Address: Nutanhat, Mongolkote, Purba Burdwan, West Bengal, India, 713147
 * 
 * © 2026 RSK World. All rights reserved.
 * Content used for educational purposes only.
 */

use hyper::header::{HeaderName, HeaderValue};
use hyper::{Body, Request, Response};
use std::collections::HashMap;
use std::net::IpAddr;
use std::str::FromStr;
use tracing::{debug, warn};

/// Extract client IP from request
pub fn extract_client_ip(req: &Request<Body>) -> Option<String> {
    // Try X-Forwarded-For header first (for proxied requests)
    if let Some(forwarded) = req.headers().get("x-forwarded-for") {
        if let Ok(forwarded_str) = forwarded.to_str() {
            // X-Forwarded-For can contain multiple IPs, take the first one
            if let Some(first_ip) = forwarded_str.split(',').next() {
                return Some(first_ip.trim().to_string());
            }
        }
    }

    // Try X-Real-IP header
    if let Some(real_ip) = req.headers().get("x-real-ip") {
        if let Ok(ip_str) = real_ip.to_str() {
            return Some(ip_str.to_string());
        }
    }

    // Fall back to remote address (not directly available in hyper::Request)
    // This would need to be extracted at the connection level in a real implementation
    Some("127.0.0.1".to_string())
}

/// Parse query parameters from URI
pub fn parse_query_params(uri: &hyper::Uri) -> HashMap<String, String> {
    let mut params = HashMap::new();
    
    if let Some(query) = uri.query() {
        for pair in query.split('&') {
            if let Some((key, value)) = pair.split_once('=') {
                params.insert(
                    urlencoding::decode(key).unwrap_or_default().to_string(),
                    urlencoding::decode(value).unwrap_or_default().to_string(),
                );
            } else {
                params.insert(
                    urlencoding::decode(pair).unwrap_or_default().to_string(),
                    String::new(),
                );
            }
        }
    }
    
    params
}

/// Validate IP address
pub fn is_valid_ip(ip_str: &str) -> bool {
    IpAddr::from_str(ip_str).is_ok()
}

/// Check if IP is in private range
pub fn is_private_ip(ip: &IpAddr) -> bool {
    match ip {
        IpAddr::V4(ipv4) => {
            ipv4.is_private() || ipv4.is_loopback() || ipv4.is_link_local()
        }
        IpAddr::V6(ipv6) => {
            ipv6.is_loopback() || ipv6.is_unique_local()
        }
    }
}

/// Convert headers to HashMap
pub fn headers_to_map(headers: &hyper::HeaderMap) -> HashMap<String, String> {
    let mut map = HashMap::new();
    
    for (name, value) in headers {
        if let (Ok(name_str), Ok(value_str)) = (name.to_str(), value.to_str()) {
            map.insert(name_str.to_lowercase(), value_str.to_string());
        }
    }
    
    map
}

/// Generate random string for IDs
pub fn generate_random_string(length: usize) -> String {
    use rand::Rng;
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                             abcdefghijklmnopqrstuvwxyz\
                             0123456789";
    let mut rng = rand::thread_rng();
    
    (0..length)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect()
}

/// Format bytes to human readable string
pub fn format_bytes(bytes: u64) -> String {
    const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
    let mut size = bytes as f64;
    let mut unit_index = 0;
    
    while size >= 1024.0 && unit_index < UNITS.len() - 1 {
        size /= 1024.0;
        unit_index += 1;
    }
    
    if unit_index == 0 {
        format!("{} {}", bytes, UNITS[unit_index])
    } else {
        format!("{:.2} {}", size, UNITS[unit_index])
    }
}

/// Validate file path for security
pub fn validate_file_path(path: &str, base_dir: &str) -> bool {
    use std::path::Path;
    
    let path = Path::new(path);
    let base = Path::new(base_dir);
    
    // Check for directory traversal attempts
    if path.components().any(|c| matches!(c, std::path::Component::ParentDir)) {
        return false;
    }
    
    // Check if path is absolute (should be relative to base)
    if path.is_absolute() {
        return false;
    }
    
    // Additional checks can be added here
    true
}

/// Get content type based on file extension
pub fn get_content_type(file_path: &str) -> &'static str {
    let path = std::path::Path::new(file_path);
    
    match path.extension().and_then(|ext| ext.to_str()) {
        Some("html") => "text/html",
        Some("css") => "text/css",
        Some("js") => "application/javascript",
        Some("json") => "application/json",
        Some("xml") => "application/xml",
        Some("txt") => "text/plain",
        Some("png") => "image/png",
        Some("jpg") | Some("jpeg") => "image/jpeg",
        Some("gif") => "image/gif",
        Some("svg") => "image/svg+xml",
        Some("ico") => "image/x-icon",
        Some("pdf") => "application/pdf",
        Some("zip") => "application/zip",
        Some("mp4") => "video/mp4",
        Some("webm") => "video/webm",
        Some("mp3") => "audio/mpeg",
        Some("wav") => "audio/wav",
        Some("woff") => "font/woff",
        Some("woff2") => "font/woff2",
        Some("ttf") => "font/ttf",
        Some("eot") => "application/vnd.ms-fontobject",
        _ => "application/octet-stream",
    }
}

/// URL encode a string
pub fn url_encode(input: &str) -> String {
    urlencoding::encode(input).to_string()
}

/// URL decode a string
pub fn url_decode(input: &str) -> Result<String, urlencoding::FromUtf8Error> {
    urlencoding::decode(input).map(|decoded| decoded.to_string())
}

/// Create JSON response with proper headers
pub fn create_json_response(status: hyper::StatusCode, body: serde_json::Value) -> Response<Body> {
    match serde_json::to_string_pretty(&body) {
        Ok(json_str) => Response::builder()
            .status(status)
            .header("content-type", "application/json")
            .body(Body::from(json_str))
            .unwrap_or_else(|_| Response::builder()
                .status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
                .body(Body::from("Failed to create JSON response"))
                .unwrap()),
        Err(_) => Response::builder()
            .status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
            .body(Body::from("Failed to serialize JSON"))
            .unwrap(),
    }
}

/// Create HTML response with proper headers
pub fn create_html_response(status: hyper::StatusCode, html: String) -> Response<Body> {
    Response::builder()
        .status(status)
        .header("content-type", "text/html; charset=utf-8")
        .body(Body::from(html))
        .unwrap()
}

/// Create redirect response
pub fn create_redirect_response(location: &str) -> Response<Body> {
    Response::builder()
        .status(hyper::StatusCode::FOUND)
        .header("location", location)
        .body(Body::empty())
        .unwrap()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_format_bytes() {
        assert_eq!(format_bytes(500), "500 B");
        assert_eq!(format_bytes(1536), "1.50 KB");
        assert_eq!(format_bytes(1048576), "1.00 MB");
        assert_eq!(format_bytes(1073741824), "1.00 GB");
    }

    #[test]
    fn test_get_content_type() {
        assert_eq!(get_content_type("index.html"), "text/html");
        assert_eq!(get_content_type("style.css"), "text/css");
        assert_eq!(get_content_type("script.js"), "application/javascript");
        assert_eq!(get_content_type("image.png"), "image/png");
        assert_eq!(get_content_type("unknown.xyz"), "application/octet-stream");
    }

    #[test]
    fn test_validate_file_path() {
        assert!(validate_file_path("safe/file.txt", "/base"));
        assert!(!validate_file_path("../unsafe.txt", "/base"));
        assert!(!validate_file_path("/absolute/path", "/base"));
        assert!(!validate_file_path("../../../etc/passwd", "/base"));
    }

    #[test]
    fn test_generate_random_string() {
        let s1 = generate_random_string(10);
        let s2 = generate_random_string(10);
        
        assert_eq!(s1.len(), 10);
        assert_eq!(s2.len(), 10);
        assert_ne!(s1, s2);
    }

    #[test]
    fn test_url_encoding() {
        let original = "hello world!";
        let encoded = url_encode(original);
        let decoded = url_decode(&encoded).unwrap();
        
        assert_eq!(original, decoded);
        assert!(encoded.contains("%20"));
    }

    #[test]
    fn test_is_valid_ip() {
        assert!(is_valid_ip("127.0.0.1"));
        assert!(is_valid_ip("::1"));
        assert!(!is_valid_ip("invalid.ip"));
        assert!(!is_valid_ip("256.256.256.256"));
    }

    #[test]
    fn test_parse_query_params() {
        let uri = hyper::Uri::builder()
            .path_and_query("/test?name=John&age=25&city=New+York")
            .build()
            .unwrap();
        
        let params = parse_query_params(&uri);
        
        assert_eq!(params.get("name"), Some(&"John".to_string()));
        assert_eq!(params.get("age"), Some(&"25".to_string()));
        assert_eq!(params.get("city"), Some(&"New York".to_string()));
    }
}
303 lines•9.6 KB
rust

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer