cgirs 1.1.0

An Rust Library for CGI Programming
Documentation
//! 定義 CGI (RFC 3875) Programming 核心函數庫
//!
//! # Remarks
//!
//! `cgirs` 庫採用類似 C/Perl CGI Programming 編程風格 且 提供 CGI Programming
//! 編程所需要的最核心函數 結合其他庫 即可實現一個具有實用功能的 CGI Programming 腳本
//!
//! # Examples
//!
//! ```cargo
//! extern crate cgirs;
//!
//! fn main() {
//!     cgirs::write("Content-Type: text/plain");
//!     cgirs::write("");
//!     cgirs::write("Hello World");
//! }
//! ```
use std::env;
use std::io::{self, Read, Write};

/// 獲取 CGI Programming 給定名稱 `key` 的環境變量值
///
/// # Remarks
/// 若給定名稱 `key` 不存在 則返回 **空字符串**
///
/// CGI (RFC 3875) Programming 環境變量常用項
///
/// * HTTP_HOST - 客戶端用於發送請求的域名地址
///
/// * HTTP_USER_AGENT - 客戶端用於發送請求的瀏覽器基本信息
///
/// * HTTP_ACCEPT - 客戶端用於發送請求的MIME類型信息
///
/// * HTTP_ACCEPT_LANGUAGE - 客戶端用於發送請求的瀏覽器語言代碼
///
/// * HTTP_ACCEPT_ENCODING - 客戶端用於發送請求的瀏覽器數據編碼
///
/// * HTTP_ACCEPT_CHARSET - 客戶端用於發送請求的瀏覽器字符集編碼
///
/// * CONTENT_TYPE - 客戶端用於發送請求的表單數據編碼類型
///
/// * CONTENT_LENGTH - 客戶端用於發送請求的表單數據長度
///
/// * HTTP_COOKIE - 客戶端用於發送請求的附加COOKIE信息
///
/// * HTTP_CONNECTION - 客戶端用於發送請求的瀏覽器鏈接模式
///
/// * SERVER_NAME - 執行當前腳本的服務器的主機名、DNS別名或者IP地址
///
/// * SERVER_ADDR - 執行當前腳本的服務器的IP地址
///
/// * SERVER_PORT - 執行當前腳本的服務器的端口
///
/// * REMOTE_HOST - 客戶端訪問當前頁面的主機名
///
/// * REMOTE_ADDR - 客戶端訪問當前頁面的IP地址
///
/// * REMOTE_PORT - 客戶端訪問當前頁面的端口
///
/// * GATEWAY_INTERFACE - 執行當前腳本的服務器所遵循的CGI規範版本信息
///
/// * SERVER_SOFTWARE - 執行當前腳本的服務器軟件名稱及其版本信息
///
/// * SERVER_PROTOCOL - 客戶端用於發送請求的協議名稱及其版本
///
/// * REQUEST_METHOD - 客戶端用於發送請求的請求方法
///
/// * QUERY_STRING - 執行當前腳本的URL地址所包含的查詢字符串
///
/// * REQUEST_URI - 執行當前腳本的URI地址
///
/// * SCRIPT_NAME - 執行當前腳本的虛擬路勁
///
/// * SCRIPT_FILENAME - 執行當前腳本的完整路徑
///
/// # Examples
///
/// ```
/// extern crate cgirs;
///
/// fn main() {
///     cgirs::write("Content-Type: text/plain");
///     cgirs::write("");
///     cgirs::write(cgirs::getenv("REQUEST_METHOD").as_str());
/// }
/// ```
pub fn getenv(key: &str) -> String {
    match env::var(key) {
        Ok(val) => val,
        Err(_) => "".to_string(),
    }
}

/// 獲取 CGI Programming 請求數據字節流
///
/// # Remarks
/// 若請求數據不存在 或者 讀取異常 則返回 **空字節流**
///
/// # Examples
///
/// ```
/// extern crate cgirs;
///
/// fn main() {
///     cgirs::write("Content-Type: text/plain");
///     cgirs::write("");
///     cgirs::write(std::str::from_utf8(&cgirs::getbody()).unwrap_or(""));
/// }
/// ```
pub fn getbody() -> Vec<u8> {
    let len: usize = getenv("CONTENT_LENGTH").parse::<usize>().unwrap_or(0);
    let mut buf: Vec<u8> = vec![0; len];

    match io::stdin().read_exact(&mut buf) {
        Ok(_) => buf,
        Err(_) => Vec::<u8>::new(),
    }
}

/// 標準輸出 CGI Programming 響應緩衝數據 並且 自動添加 `換行符`
///
/// # Examples
///
/// ```
/// extern crate cgirs;
///
/// fn main() {
///     cgirs::write("Content-Type: text/plain");
///     cgirs::write("");
///     cgirs::write("Response Data");
/// }
/// ```
pub fn write(buf: &str) -> () {
    io::stdout()
        .write((buf.to_owned() + "\r\n").as_bytes())
        .unwrap();
}

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

    #[test]
    fn test_getenv() {
        assert!(!getenv("PATH").is_empty());
    }

    #[test]
    fn test_getbody() {
        assert_eq!(0, getbody().len());
    }

    #[test]
    fn test_write() {
        assert_eq!((), write("Content-Type: text/plain"));
    }
}