From c1d969724401532ce7bdbb4c9ad616c938b92acb Mon Sep 17 00:00:00 2001 From: owent Date: Fri, 19 May 2023 18:39:19 +0800 Subject: [PATCH] Add `static_root` and fix escape Signed-off-by: owent --- CHANGELOG.md | 6 ++++ Cargo.lock | 57 ++++++++++++++++++++++++++++++++++++- Cargo.toml | 8 ++---- README.md | 2 +- etc/conf.json | 1 + src/app.rs | 16 ++++++++++- src/handles/robot.rs | 1 + src/main.rs | 31 +++++++++++++------- src/wxwork_robot/message.rs | 52 +++++++++++---------------------- 9 files changed, 120 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa1974c..f876999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ============ +v0.10.1 +---------- + +1. 修复回包的espace问题 +2. 增加 `static_root` 选项,以便用于设置静态文件 + v0.10.0 ---------- diff --git a/Cargo.lock b/Cargo.lock index 098a068..070ef6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-files" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" +dependencies = [ + "actix-http", + "actix-service", + "actix-utils", + "actix-web", + "askama_escape", + "bitflags", + "bytes", + "derive_more", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", +] + [[package]] name = "actix-http" version = "3.3.1" @@ -317,6 +340,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + [[package]] name = "autocfg" version = "1.1.0" @@ -898,6 +927,12 @@ dependencies = [ "itoa 1.0.1", ] +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + [[package]] name = "httparse" version = "1.5.1" @@ -1107,6 +1142,16 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1797,6 +1842,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.7" @@ -2115,8 +2169,9 @@ dependencies = [ [[package]] name = "wxwork_robotd" -version = "0.10.0" +version = "0.10.1" dependencies = [ + "actix-files", "actix-web", "aes", "awc", diff --git a/Cargo.toml b/Cargo.toml index 4fd3358..49662bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ license = "MIT OR Apache-2.0" name = "wxwork_robotd" readme = "README.md" repository = "https://github.com/owent/wxwork_robotd" -version = "0.10.0" +version = "0.10.1" [[bin]] name = "wxwork_robotd" @@ -49,10 +49,8 @@ cbc = ">=0.1.2" md-5 = ">=0.10.0" cipher = { version = ">=0.4.0", features = ["alloc"] } # https://github.com/RustCrypto - -[dependencies.actix-web] -features = ["rustls"] -version = "^4.3.0" +actix-web = { version = "^4.3.0", features = ["rustls"] } +actix-files = { version = ">=0.6.2" } [dependencies.awc] features = ["rustls"] diff --git a/README.md b/README.md index e8108cf..9ea4e50 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ ```javascript { "listen": ["0.0.0.0:12019", ":::12019"], // 监听列表,这里配置了ipv4和ipv6地址 - "taskTimeout": 4000, // 超时时间4000ms,企业微信要求在5秒内回应,这里容忍1秒钟的网络延迟 + "task_timeout": 4000, // 超时时间4000ms,企业微信要求在5秒内回应,这里容忍1秒钟的网络延迟 "workers": 8, // 工作线程数 "backlog": 256, // 建立连接的排队长度 "keep_alive": 5, // tcp保持连接的心跳间隔(秒) (版本: >=0.6.0) diff --git a/etc/conf.json b/etc/conf.json index f8979fc..2f39638 100644 --- a/etc/conf.json +++ b/etc/conf.json @@ -9,6 +9,7 @@ "max_connection_per_worker": 20480, "max_concurrent_rate_per_worker": 256, "payload_size_limit": 262144, + "static_root": ".", "cmds": { "default": { "type": "echo", diff --git a/src/app.rs b/src/app.rs index 1fb3c14..ce41b16 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,7 +1,7 @@ use std::fs::{create_dir_all, OpenOptions}; use std::io::Write; use std::net::ToSocketAddrs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process; use std::rc::Rc; use std::str::FromStr; @@ -25,6 +25,7 @@ pub struct AppConfigure { pub max_connection_per_worker: usize, pub max_concurrent_rate_per_worker: usize, pub payload_size_limit: usize, + pub static_root: Option, } #[derive(Debug, Clone, Copy)] @@ -75,6 +76,7 @@ static mut APP_ENV_INFO_STORE: AppEnvironmentInfo = AppEnvironmentInfo { max_connection_per_worker: 20480, max_concurrent_rate_per_worker: 256, payload_size_limit: 262144, // 256KB + static_root: None, }, }; @@ -621,6 +623,18 @@ impl AppEnvironment { } } + if let Some(x) = kvs.get("static_root") { + if let Some(v) = x.as_str() { + if !v.is_empty() { + if let Ok(root_path) = PathBuf::from_str(v) { + unsafe { + APP_ENV_INFO_STORE.conf.static_root = Some(root_path); + } + } + } + } + } + { let mut hosts = Vec::new(); if let Some(x) = kvs.get("listen") { diff --git a/src/handles/robot.rs b/src/handles/robot.rs index 0278a99..fcfb5a0 100644 --- a/src/handles/robot.rs +++ b/src/handles/robot.rs @@ -56,6 +56,7 @@ pub async fn dispatch_robot_request( if let Ok(x) = web::Query::::from_query(req.query_string()) { return dispatch_robot_message(app, Arc::new(project_name), x.into_inner(), body).await; } + make_robot_error_response_future("parameter error.") } diff --git a/src/main.rs b/src/main.rs index c192c2c..c4fb993 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ static GLOBAL: System = System; // crates #[macro_use] extern crate clap; +extern crate actix_files; extern crate actix_web; extern crate awc; extern crate futures; @@ -37,7 +38,9 @@ extern crate tokio; // import packages // use std::sync::Arc; +use crate::actix_files::Files; use actix_web::{middleware::Logger, web, App, HttpServer}; + use std::io; use std::net::TcpListener; use std::time::Duration; @@ -78,21 +81,29 @@ async fn main() -> io::Result<()> { let reg_move_default = app_env; let reg_move_robot = app_env; - app + let app = app // ====== register for index ====== .service( web::resource(app_env.prefix.to_string()) .app_data(web::PayloadConfig::default().limit(app_env.conf.payload_size_limit)) .to(move |req| handles::default::dispatch_default_index(reg_move_default, req)), - ) - // ====== register for project ====== - .service( - web::resource(format!("{}{{project}}/", app_env.prefix).as_str()) - .app_data(web::PayloadConfig::default().limit(app_env.conf.payload_size_limit)) - .to(move |req, body| { - handles::robot::dispatch_robot_request(reg_move_robot, req, body) - }), - ) + ); + + // ====== register for static files ====== + let app = if let Some(static_root) = app_env.conf.static_root.as_ref() { + app.service(Files::new("/", static_root).show_files_listing()) + } else { + app + }; + + // ====== register for project ====== + app.service( + web::resource(format!("{}{{project}}/", app_env.prefix).as_str()) + .app_data(web::PayloadConfig::default().limit(app_env.conf.payload_size_limit)) + .to(move |req, body| { + handles::robot::dispatch_robot_request(reg_move_robot, req, body) + }), + ) // app_env.setup(app) }); diff --git a/src/wxwork_robot/message.rs b/src/wxwork_robot/message.rs index 1bb0feb..7e4d1c5 100644 --- a/src/wxwork_robot/message.rs +++ b/src/wxwork_robot/message.rs @@ -595,9 +595,7 @@ pub fn pack_text_message(msg: WxWorkMessageTextRsp) -> Result { .write_event(Event::Start(BytesStart::new("Content"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new( - quick_xml::escape::escape(msg.content.as_str()), - ))); + let _ = writer.write_event(Event::CData(BytesCData::new(msg.content))); let _ = writer.write_event(Event::End(BytesEnd::new("Content"))); } @@ -610,9 +608,7 @@ pub fn pack_text_message(msg: WxWorkMessageTextRsp) -> Result { .write_event(Event::Start(BytesStart::new("Item"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new( - quick_xml::escape::escape(v.as_str()), - ))); + let _ = writer.write_event(Event::CData(BytesCData::new(v))); let _ = writer.write_event(Event::End(BytesEnd::new("Item"))); } } @@ -628,9 +624,7 @@ pub fn pack_text_message(msg: WxWorkMessageTextRsp) -> Result { .write_event(Event::Start(BytesStart::new("Item"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new( - quick_xml::escape::escape(v.to_string().as_str()), - ))); + let _ = writer.write_event(Event::CData(BytesCData::new(v.to_string()))); let _ = writer.write_event(Event::End(BytesEnd::new("Item"))); } } @@ -673,9 +667,7 @@ pub fn pack_markdown_message(msg: WxWorkMessageMarkdownRsp) -> Result Result .write_event(Event::Start(BytesStart::new("MsgType"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new(quick_xml::escape::escape( - "image", - )))); + let _ = writer.write_event(Event::CData(BytesCData::new("image"))); let _ = writer.write_event(Event::End(BytesEnd::new("MsgType"))); } @@ -717,14 +707,12 @@ pub fn pack_image_message(msg: WxWorkMessageImageRsp) -> Result .is_ok() { // BytesText::from_escaped_str - let _ = - writer.write_event(Event::CData(BytesCData::new(quick_xml::escape::escape( - match base64::STANDARD.encode(&msg.content) { - Ok(x) => x, - Err(e) => e.message, - } - .as_str(), - )))); + let _ = writer.write_event(Event::CData(BytesCData::new( + match base64::STANDARD.encode(&msg.content) { + Ok(x) => x, + Err(e) => e.message, + }, + ))); let _ = writer.write_event(Event::End(BytesEnd::new("Base64"))); } @@ -737,7 +725,7 @@ pub fn pack_image_message(msg: WxWorkMessageImageRsp) -> Result { // BytesText::from_escaped_str let _ = writer.write_event(Event::CData(BytesCData::new( - quick_xml::escape::escape(hex::encode(hasher.finalize().as_slice()).as_str()), + hex::encode(hasher.finalize().as_slice()).as_str(), ))); let _ = writer.write_event(Event::End(BytesEnd::new("Md5"))); } @@ -769,9 +757,7 @@ pub fn pack_message_response( .write_event(Event::Start(BytesStart::new("Encrypt"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new(quick_xml::escape::escape( - encrypt.as_str(), - )))); + let _ = writer.write_event(Event::CData(BytesCData::new(encrypt.as_str()))); let _ = writer.write_event(Event::End(BytesEnd::new("Encrypt"))); } @@ -779,9 +765,7 @@ pub fn pack_message_response( .write_event(Event::Start(BytesStart::new("MsgSignature"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new(quick_xml::escape::escape( - msg_signature.as_str(), - )))); + let _ = writer.write_event(Event::CData(BytesCData::new(msg_signature.as_str()))); let _ = writer.write_event(Event::End(BytesEnd::new("MsgSignature"))); } @@ -797,9 +781,7 @@ pub fn pack_message_response( .write_event(Event::Start(BytesStart::new("Nonce"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new(quick_xml::escape::escape( - nonce.as_str(), - )))); + let _ = writer.write_event(Event::CData(BytesCData::new(nonce.as_str()))); let _ = writer.write_event(Event::End(BytesEnd::new("Nonce"))); } @@ -830,9 +812,7 @@ pub fn get_robot_response_access_deny_content(msg: &str) -> String { .write_event(Event::Start(BytesStart::new("message"))) .is_ok() { - let _ = writer.write_event(Event::CData(BytesCData::new(quick_xml::escape::escape( - msg, - )))); + let _ = writer.write_event(Event::CData(BytesCData::new(msg))); let _ = writer.write_event(Event::End(BytesEnd::new("message"))); }