-- Leo's gemini proxy
-- Connecting to typed-hole.org:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini
commit 15846feec2f3d66906ccd6bbd0ed2fdd129fe60e
Author: Julien Blanchard <julien@sideburns.eu>
Date: Fri Oct 4 11:56:58 2019 +0200
Don't try to display non-text content in the SelectView
Fix a bug where opening an image was making Asuka crash
after closing the external viewer.
diff --git a/src/content.rs b/src/content.rs
index 1606dab..184d9e4 100644
--- a/src/content.rs
+++ b/src/content.rs
@@ -1,5 +1,5 @@
-use tempfile::NamedTempFile;
use std::io::{Read, Write};
+use tempfile::NamedTempFile;
use native_tls::TlsConnector;
use std::net::{TcpStream, ToSocketAddrs};
@@ -30,7 +30,7 @@ pub fn get_data(url: &url::Url) -> Result<(Vec<u8>, Vec<u8>), String> {
let mut res = vec![];
stream.read_to_end(&mut res).unwrap();
- let clrf_idx = find_subsequence(&res, b"\r\n");
+ let clrf_idx = find_clrf(&res);
let content = res.split_off(clrf_idx.unwrap() + 2);
Ok((res, content))
@@ -43,7 +43,7 @@ pub fn get_data(url: &url::Url) -> Result<(Vec<u8>, Vec<u8>), String> {
}
None => Err(format!("Could not connect to {}", urlf)),
},
- Err(e) => Err(format!("Could not connect to {}\n{}", urlf, e))
+ Err(e) => Err(format!("Could not connect to {}\n{}", urlf, e)),
}
}
@@ -59,6 +59,7 @@ fn write_tmp_file(content: Vec<u8>) -> std::path::PathBuf {
path
}
-fn find_subsequence(haystack: &[u8], needle: &[u8]) -> Option<usize> {
- haystack.windows(needle.len()).position(|window| window == needle)
+fn find_clrf(data: &[u8]) -> Option<usize> {
+ let clrf = b"\r\n";
+ data.windows(clrf.len()).position(|window| window == clrf)
}
diff --git a/src/history.rs b/src/history.rs
index e64edb1..ca29775 100644
--- a/src/history.rs
+++ b/src/history.rs
@@ -1,5 +1,5 @@
-use url::Url;
use std::sync::Mutex;
+use url::Url;
lazy_static! {
static ref HISTORY: Mutex<Vec<Url>> = Mutex::new(vec![]);
@@ -23,13 +23,11 @@ pub fn append(url: &str) {
pub fn get_current_host() -> Option<String> {
let history = HISTORY.lock().unwrap();
match history.last() {
- Some(current_url) => {
- match current_url.host_str() {
- Some(host) => Some(String::from(host)),
- None => None
- }
- }
- None => None
+ Some(current_url) => match current_url.host_str() {
+ Some(host) => Some(String::from(host)),
+ None => None,
+ },
+ None => None,
}
}
@@ -40,9 +38,9 @@ pub fn get_current_url() -> Option<String> {
let current_path = current_url.join("./");
match current_path {
Ok(path) => Some(path.to_string()),
- Err(_) => None
+ Err(_) => None,
}
}
- None => None
+ None => None,
}
}
diff --git a/src/link.rs b/src/link.rs
index a1aa1ff..c9ac638 100644
--- a/src/link.rs
+++ b/src/link.rs
@@ -1,8 +1,8 @@
extern crate regex;
+use json::JsonValue;
use regex::Regex;
-use url::Url;
use std::str::FromStr;
-use json::JsonValue;
+use url::Url;
pub enum Link {
@@ -50,19 +50,15 @@ impl FromStr for Link {
fn make_link(url: String, label: String) -> Option<Link> {
let urlp = Url::parse(&url);
match urlp {
- Ok(url) => {
- match url.scheme() {
- "gemini" => Some(Link::Gemini(url, label)),
- "gopher" => Some(Link::Gopher(url, label)),
- "http" => Some(Link::Http(url, label)),
- "https" => Some(Link::Http(url, label)),
- _ => Some(Link::Unknown(url, label))
- }
- },
- Err(url::ParseError::RelativeUrlWithoutBase) => {
- Some(Link::Relative(url, label))
+ Ok(url) => match url.scheme() {
+ "gemini" => Some(Link::Gemini(url, label)),
+ "gopher" => Some(Link::Gopher(url, label)),
+ "http" => Some(Link::Http(url, label)),
+ "https" => Some(Link::Http(url, label)),
+ _ => Some(Link::Unknown(url, label)),
},
- _ => None
+ Err(url::ParseError::RelativeUrlWithoutBase) => Some(Link::Relative(url, label)),
+ _ => None,
}
}
diff --git a/src/main.rs b/src/main.rs
index 4ee3a51..13051c5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -23,9 +23,9 @@ use status::Status;
mod link;
use link::Link;
+mod absolute;
mod content;
mod history;
-mod absolute;
const HELP: &str = "Welcome to Asuka Gemini browser!
@@ -151,15 +151,15 @@ fn visit_url(s: &mut Cursive, url: &Url) {
}
match absolute::make(url.as_str()) {
- Ok(url) => {
- match content::get_data(&url) {
- Ok((meta, new_content)) => {
- history::append(url.as_str());
- draw_content(s, &url, meta, new_content);
- }
- Err(msg) => {
- s.add_layer(Dialog::info(msg));
- }
+ Ok(url) => match content::get_data(&url) {
+ Ok((meta, new_content)) => {
+ history::append(url.as_str());
+ // handle meta header
+ let response = handle_response_status(s, &url, meta, new_content);
+ draw_content(s, &url, response);
+ }
+ Err(msg) => {
+ s.add_layer(Dialog::info(msg));
}
},
Err(_) => {
@@ -168,87 +168,12 @@ fn visit_url(s: &mut Cursive, url: &Url) {
}
}
-fn draw_content(s: &mut Cursive, url: &Url, meta: Vec<u8>, content: Vec<u8>) {
- let content_str = String::from_utf8_lossy(&content).to_string();
-
- // handle meta header
- handle_response_status(s, url, meta, content);
-
- let mut main_view = match s.find_id::<SelectView>("main") {
- Some(view) => view,
- None => panic!("Can't find main view."),
- };
-
- // set title and clear old content
- set_title(s, url.as_str());
- main_view.clear();
-
- // draw new content lines
- for line in content_str.lines() {
- match Link::from_str(line) {
- Ok(link) => match link {
- Link::Http(url, label) => {
- let mut formatted = StyledString::new();
- let www_label = format!("{} [WWW]", label);
- formatted.append(StyledString::styled(
- www_label,
- Style::from(Color::Dark(BaseColor::Green)).combine(Effect::Bold),
- ));
-
- let data = object! {
- "type" => "www",
- "url" => url.to_string()
- };
- main_view.add_item(formatted, json::stringify(data))
- }
- Link::Gopher(url, label) => {
- let mut formatted = StyledString::new();
- let gopher_label = format!("{} [Gopher]", label);
- formatted.append(StyledString::styled(
- gopher_label,
- Style::from(Color::Light(BaseColor::Magenta)).combine(Effect::Bold),
- ));
-
- let data = object! {
- "type" => "gopher",
- "url" => url.to_string()
- };
- main_view.add_item(formatted, json::stringify(data))
- }
- Link::Gemini(url, label) => {
- let mut formatted = StyledString::new();
- formatted.append(StyledString::styled(
- label,
- Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),
- ));
-
- let data = object! {
- "type" => "gemini",
- "url" => url.to_string()
- };
- main_view.add_item(formatted, json::stringify(data))
- }
- Link::Relative(url, label) => {
- let mut formatted = StyledString::new();
- formatted.append(StyledString::styled(
- label,
- Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),
- ));
-
- let data = object! {
- "type" => "gemini",
- "url" => url.to_string()
- };
- main_view.add_item(formatted, json::stringify(data))
- }
- Link::Unknown(_, _) => (),
- },
- Err(_) => main_view.add_item(str::replace(line, "\t", " "), String::from("0")),
- }
- }
-}
-
-fn handle_response_status(s: &mut Cursive, url: &Url, meta: Vec<u8>, content: Vec<u8>) {
+fn handle_response_status(
+ s: &mut Cursive,
+ url: &Url,
+ meta: Vec<u8>,
+ content: Vec<u8>,
+) -> Option<Vec<u8>> {
let url_copy = url.clone();
let meta_str = String::from_utf8_lossy(&meta).to_string();
@@ -257,38 +182,126 @@ fn handle_response_status(s: &mut Cursive, url: &Url, meta: Vec<u8>, content: Ve
Status::Success(meta) => {
if meta.starts_with("text/") {
// display text files.
- {}
+ Some(content)
} else {
// download and try to open the rest.
content::download(content);
- return;
+ None
}
}
Status::Gone(_meta) => {
s.add_layer(Dialog::info("Sorry page is gone."));
- return;
+ None
}
Status::RedirectTemporary(new_url) | Status::RedirectPermanent(new_url) => {
- return follow_link(s, &new_url)
+ follow_link(s, &new_url);
+ None
}
Status::TransientCertificateRequired(_meta)
| Status::AuthorisedCertificatedRequired(_meta) => {
s.add_layer(Dialog::info(
"You need a valid certificate to access this page.",
));
- return;
+ None
}
Status::Input(message) => {
prompt_for_answer(s, url_copy, message);
+ None
}
other_status => {
s.add_layer(Dialog::info(format!("ERROR: {:?}", other_status)));
- return;
+ None
}
}
+ } else {
+ None
}
}
+fn draw_content(s: &mut Cursive, url: &Url, content: Option<Vec<u8>>) {
+ match content {
+ Some(data) => {
+ let mut main_view = match s.find_id::<SelectView>("main") {
+ Some(view) => view,
+ None => panic!("Can't find main view."),
+ };
+
+ // set title and clear old content
+ set_title(s, url.as_str());
+ main_view.clear();
+
+ let content_str = String::from_utf8_lossy(&data).to_string();
+
+ // draw new content lines
+ for line in content_str.lines() {
+ match Link::from_str(line) {
+ Ok(link) => match link {
+ Link::Http(url, label) => {
+ let mut formatted = StyledString::new();
+ let www_label = format!("{} [WWW]", label);
+ formatted.append(StyledString::styled(
+ www_label,
+ Style::from(Color::Dark(BaseColor::Green)).combine(Effect::Bold),
+ ));
+
+ let data = object! {
+ "type" => "www",
+ "url" => url.to_string()
+ };
+ main_view.add_item(formatted, json::stringify(data))
+ }
+ Link::Gopher(url, label) => {
+ let mut formatted = StyledString::new();
+ let gopher_label = format!("{} [Gopher]", label);
+ formatted.append(StyledString::styled(
+ gopher_label,
+ Style::from(Color::Light(BaseColor::Magenta)).combine(Effect::Bold),
+ ));
+
+ let data = object! {
+ "type" => "gopher",
+ "url" => url.to_string()
+ };
+ main_view.add_item(formatted, json::stringify(data))
+ }
+ Link::Gemini(url, label) => {
+ let mut formatted = StyledString::new();
+ formatted.append(StyledString::styled(
+ label,
+ Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),
+ ));
+
+ let data = object! {
+ "type" => "gemini",
+ "url" => url.to_string()
+ };
+ main_view.add_item(formatted, json::stringify(data))
+ }
+ Link::Relative(url, label) => {
+ let mut formatted = StyledString::new();
+ formatted.append(StyledString::styled(
+ label,
+ Style::from(Color::Light(BaseColor::Blue)).combine(Effect::Bold),
+ ));
+
+ let data = object! {
+ "type" => "gemini",
+ "url" => url.to_string()
+ };
+ main_view.add_item(formatted, json::stringify(data))
+ }
+ Link::Unknown(_, _) => (),
+ },
+ Err(_) => {
+ main_view.add_item(str::replace(line, "\t", " "), String::from("0"))
+ }
+ }
+ }
+ }
+ None => (),
+ };
+}
+
fn set_title(s: &mut Cursive, text: &str) {
let mut container = match s.find_id::<Dialog>("container") {
Some(view) => view,
diff --git a/src/status.rs b/src/status.rs
index 93d69d5..2b70940 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -79,6 +79,6 @@ fn make_status(code: i16, meta: String) -> Status {
63 => Status::CertificateNotAccepted(meta),
64 => Status::FutureCertificateRejected(meta),
65 => Status::ExpiredCertificateRejected(meta),
- _ => Status::Unknown(meta)
+ _ => Status::Unknown(meta),
}
}
---
Served by Pollux Gemini Server.
-- Response ended
-- Page fetched on Sun May 19 12:17:57 2024