🏗️ Elegant & Highly Performant Async Gemini Server Framework for the Modern Age
async framework gemini-protocol protocol gemini rust
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(response): always allow explicit mime specification

Fuwn 32d10fa0 b28f5029

+18 -121
+1 -1
Cargo.toml
··· 2 2 3 3 [package] 4 4 name = "windmark" 5 - version = "0.1.16" 5 + version = "0.1.17" 6 6 authors = ["Fuwn <contact@fuwn.me>"] 7 7 edition = "2021" 8 8 description = "An elegant and highly performant async Gemini server framework"
+3 -3
README.md
··· 15 15 # Cargo.toml 16 16 17 17 [dependencies] 18 - windmark = "0.1.16" 18 + windmark = "0.1.17" 19 19 tokio = { version = "0.2.4", features = ["full"] } 20 20 21 21 # If you would like to use the built-in logger (recommended) 22 - # windmark = { version = "0.1.16", features = ["logger"] } 22 + # windmark = { version = "0.1.17", features = ["logger"] } 23 23 24 24 # If you would like to use the built-in MIME dedection when `Success`-ing a file 25 25 # (recommended) 26 - # windmark = { version = "0.1.16", features = ["auto-deduce-mime"] } 26 + # windmark = { version = "0.1.17", features = ["auto-deduce-mime"] } 27 27 ``` 28 28 29 29 ### Implement a Windmark server
+5 -6
examples/windmark.rs
··· 58 58 59 59 router.set_private_key_file("windmark_private.pem"); 60 60 router.set_certificate_file("windmark_public.pem"); 61 + #[cfg(feature = "logger")] 61 62 router.enable_default_logger(true); 62 63 router.set_error_handler(Box::new(move |_| { 63 64 error_count += 1; ··· 185 186 "/redirect", 186 187 Box::new(|_| Response::PermanentRedirect("gemini://localhost/test".into())), 187 188 ); 189 + #[cfg(feature = "auto-deduce-mime")] 190 + router.mount("/auto-file", { 191 + Box::new(|_| Response::SuccessFileAuto(include_bytes!("../LICENSE"))) 192 + }); 188 193 router.mount("/file", { 189 - #[cfg(feature = "auto-deduce-mime")] 190 - { 191 - Box::new(|_| Response::SuccessFile(include_bytes!("../LICENSE"))) 192 - } 193 - 194 - #[cfg(not(feature = "auto-deduce-mime"))] 195 194 Box::new(|_| { 196 195 Response::SuccessFile( 197 196 include_bytes!("../LICENSE"),
+6 -104
src/response.rs
··· 24 24 SensitiveInput(String), 25 25 Success(String), 26 26 #[cfg(feature = "auto-deduce-mime")] 27 - SuccessFile(&'a [u8]), 28 - #[cfg(not(feature = "auto-deduce-mime"))] 27 + /// A successful response where the MIME type of the response is 28 + /// automatically deduced from the provided bytes 29 + SuccessFileAuto(&'a [u8]), 29 30 SuccessFile(&'a [u8], String), 30 31 TemporaryRedirect(String), 31 32 PermanentRedirect(String), ··· 44 45 CertificateNotValid(String), 45 46 } 46 47 47 - #[cfg(not(feature = "auto-deduce-mime"))] 48 48 pub(crate) fn to_value_set_status( 49 49 response: Response<'_>, 50 50 status: &mut i32, ··· 72 72 73 73 String::from_utf8(value.to_vec()).unwrap() 74 74 } 75 - Response::TemporaryRedirect(value) => { 76 - *status = 30; 77 - 78 - value 79 - } 80 - Response::PermanentRedirect(value) => { 81 - *status = 31; 82 - 83 - value 84 - } 85 - Response::TemporaryFailure(value) => { 86 - *status = 40; 87 - 88 - value 89 - } 90 - Response::ServerUnavailable(value) => { 91 - *status = 41; 92 - 93 - value 94 - } 95 - Response::CGIError(value) => { 96 - *status = 42; 97 - 98 - value 99 - } 100 - Response::ProxyError(value) => { 101 - *status = 43; 102 - 103 - value 104 - } 105 - Response::SlowDown(value) => { 106 - *status = 44; 107 - 108 - value 109 - } 110 - Response::PermanentFailure(value) => { 111 - *status = 50; 112 - 113 - value 114 - } 115 - Response::NotFound(value) => { 116 - *status = 51; 117 - 118 - value 119 - } 120 - Response::Gone(value) => { 121 - *status = 52; 122 - 123 - value 124 - } 125 - Response::ProxyRefused(value) => { 126 - *status = 53; 127 - 128 - value 129 - } 130 - Response::BadRequest(value) => { 131 - *status = 59; 132 - 133 - value 134 - } 135 - Response::ClientCertificateRequired(value) => { 136 - *status = 60; 137 - 138 - value 139 - } 140 - Response::CertificateNotAuthorised(value) => { 141 - *status = 61; 142 - 143 - value 144 - } 145 - Response::CertificateNotValid(value) => { 146 - *status = 62; 147 - 148 - value 149 - } 150 - } 151 - } 152 - 153 - #[cfg(feature = "auto-deduce-mime")] 154 - pub(crate) fn to_value_set_status( 155 - response: Response<'_>, 156 - status: &mut i32, 157 - ) -> String { 158 - match response { 159 - Response::Input(value) => { 160 - *status = 10; 161 - 162 - value 163 - } 164 - Response::SensitiveInput(value) => { 165 - *status = 11; 166 - 167 - value 168 - } 169 - Response::Success(value) => { 170 - *status = 20; 171 - 172 - value 173 - } 174 - Response::SuccessFile(value) => { 175 - *status = 21; // Internal status code, not real. 75 + #[cfg(feature = "auto-deduce-mime")] 76 + Response::SuccessFileAuto(value) => { 77 + *status = 22; // Internal status code, not real. 176 78 177 79 String::from_utf8(value.to_vec()).unwrap() 178 80 }
+3 -7
src/router.rs
··· 261 261 let mut buffer = [0u8; 1024]; 262 262 let mut url = Url::parse("gemini://fuwn.me/")?; 263 263 let mut response_status = 0; 264 - #[cfg(not(feature = "auto-deduce-mime"))] 265 264 let mut response_mime_type = "".to_string(); 266 265 let mut footer = String::new(); 267 266 let mut header = String::new(); ··· 364 363 &stream.ssl().peer_certificate(), 365 364 ),)), 366 365 &mut response_status, 367 - #[cfg(not(feature = "auto-deduce-mime"))] 368 366 &mut response_mime_type, 369 367 ) 370 368 } else { ··· 378 376 &stream.ssl().peer_certificate(), 379 377 ),)), 380 378 &mut response_status, 381 - #[cfg(not(feature = "auto-deduce-mime"))] 382 379 &mut response_mime_type, 383 380 ) 384 381 }; ··· 387 384 .write_all( 388 385 format!( 389 386 "{}{}\r\n{}", 390 - if response_status == 21 { 387 + if response_status == 21 || response_status == 22 { 391 388 20 392 389 } else { 393 390 response_status ··· 399 396 self.charset, self.language 400 397 ), 401 398 #[cfg(feature = "auto-deduce-mime")] 402 - 21 => format!(" {}", tree_magic::from_u8(&*content.as_bytes())), 403 - #[cfg(not(feature = "auto-deduce-mime"))] 399 + 22 => format!(" {}", tree_magic::from_u8(&*content.as_bytes())), 404 400 21 => response_mime_type, 405 401 _ => format!(" {}", content), 406 402 }, 407 403 match response_status { 408 404 20 => format!("{}{}\n{}", header, content, footer), 409 - 21 => content.to_string(), 405 + 21 | 22 => content.to_string(), 410 406 _ => "".to_string(), 411 407 } 412 408 )