1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! 定義 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"));
    }
}