use smol
This commit is contained in:
parent
62350daba5
commit
30afd1126c
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,5 +1,17 @@
|
|||
# Changelog
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### maj
|
||||
|
||||
- `maj::get` unfortunately had to become async in order for fetching `gus.guru` to work
|
||||
|
||||
### majc
|
||||
|
||||
- keep track of loaded pages as history
|
||||
- `l` to view/navigate to links
|
||||
- use [smol](https://github.com/stjepang/smol) for doing the async operations synchronously
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### maj
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "maj"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["Christine Dodrill <me@christine.website>"]
|
||||
edition = "2018"
|
||||
license = "0BSD"
|
||||
|
@ -18,6 +18,7 @@ rustls = { version = "0.18", optional = true, features = ["dangerous_configurati
|
|||
webpki = { version = "0.21.0", optional = true }
|
||||
webpki-roots = { version = "0.20", optional = true }
|
||||
tokio-rustls = { version = "0.14", features = ["dangerous_configuration"], optional = true }
|
||||
tokio-io-timeout = "0.4"
|
||||
log = "0.4"
|
||||
url = "2"
|
||||
thiserror = "1"
|
||||
|
@ -42,7 +43,7 @@ optional = true
|
|||
[features]
|
||||
default = ["client", "server"]
|
||||
|
||||
client = ["rustls", "webpki", "webpki-roots"]
|
||||
client = ["rustls", "webpki", "webpki-roots", "tokio", "tokio-rustls"]
|
||||
server = ["rustls", "webpki", "webpki-roots", "tokio", "async-trait", "tokio-rustls"]
|
||||
|
||||
[workspace]
|
||||
|
|
|
@ -10,5 +10,10 @@ edition = "2018"
|
|||
cursive = "0.15"
|
||||
log = "0.4"
|
||||
url = "2"
|
||||
webpki = "0.21.0"
|
||||
tokio-rustls = { version = "0.14", features = ["dangerous_configuration"] }
|
||||
rustls = { version = "0.18", features = ["dangerous_configuration"] }
|
||||
smol = { version = "0.3", features = ["tokio02"] }
|
||||
|
||||
maj = { path = ".." }
|
||||
|
||||
|
|
|
@ -7,13 +7,26 @@ use cursive::{
|
|||
};
|
||||
use maj::{self, Response};
|
||||
use std::str;
|
||||
use tokio_rustls::rustls::ClientConfig;
|
||||
|
||||
/// The state of the browser.
|
||||
#[derive(Default, Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct State {
|
||||
url: Option<url::Url>,
|
||||
history: Vec<url::Url>,
|
||||
links: Vec<(url::Url, Option<String>)>,
|
||||
cfg: ClientConfig,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
State {
|
||||
url: None,
|
||||
history: vec![],
|
||||
links: vec![],
|
||||
cfg: crate::tls::config(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn history(siv: &mut Cursive) {
|
||||
|
@ -100,7 +113,7 @@ pub fn open(siv: &mut Cursive, url: &str) {
|
|||
|
||||
st.url = Some(url.clone());
|
||||
|
||||
match maj::get(url.to_string()) {
|
||||
match smol::run(maj::get(url.to_string(), st.cfg.clone())) {
|
||||
Ok(resp) => {
|
||||
st.history.push(url.clone());
|
||||
show(siv, url.to_string().as_str(), resp);
|
||||
|
@ -200,14 +213,12 @@ pub fn render(body: &str) -> StyledString {
|
|||
for node in doc {
|
||||
match node {
|
||||
Text(line) => styled.append(StyledString::plain(line)),
|
||||
Link { to, name } => {
|
||||
match name {
|
||||
Link { to, name } => match name {
|
||||
None => styled.append(StyledString::styled(to, Style::from(Effect::Underline))),
|
||||
Some(name) => {
|
||||
styled.append(StyledString::styled(name, Style::from(Effect::Underline)))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Preformatted(data) => styled.append(StyledString::plain(data)),
|
||||
Heading { level, body } => styled.append(StyledString::styled(
|
||||
format!("{} {}", "#".repeat(level as usize), body),
|
||||
|
|
|
@ -3,6 +3,7 @@ use cursive::{event::Key, menu::MenuTree};
|
|||
pub(crate) mod commands;
|
||||
pub(crate) mod gemini;
|
||||
pub(crate) mod theme;
|
||||
pub(crate) mod tls;
|
||||
|
||||
fn main() {
|
||||
cursive::logger::init();
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
use tokio_rustls::rustls;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn config() -> rustls::ClientConfig {
|
||||
let mut config = rustls::ClientConfig::new();
|
||||
config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
struct NoCertificateVerification {}
|
||||
|
||||
impl rustls::ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_roots: &rustls::RootCertStore,
|
||||
_presented_certs: &[rustls::Certificate],
|
||||
_dns_name: webpki::DNSNameRef<'_>,
|
||||
_ocsp: &[u8],
|
||||
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||
Ok(rustls::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
|
@ -1,27 +1,15 @@
|
|||
use crate::Response;
|
||||
use rustls::{ClientConfig, ClientSession, Stream, TLSError};
|
||||
use std::{io::prelude::*, net::TcpStream, sync::Arc};
|
||||
use std::{io::Cursor, sync::Arc};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::TcpStream,
|
||||
};
|
||||
use tokio_rustls::{
|
||||
rustls::{TLSError},
|
||||
TlsConnector,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
fn config() -> ClientConfig {
|
||||
let mut config = ClientConfig::new();
|
||||
config.dangerous().set_certificate_verifier(Arc::new(NoCertificateVerification{}));
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
struct NoCertificateVerification {}
|
||||
|
||||
impl rustls::ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(&self,
|
||||
_roots: &rustls::RootCertStore,
|
||||
_presented_certs: &[rustls::Certificate],
|
||||
_dns_name: webpki::DNSNameRef<'_>,
|
||||
_ocsp: &[u8]) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||
Ok(rustls::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("TLS error: {0:?}")]
|
||||
|
@ -43,7 +31,7 @@ pub enum Error {
|
|||
InvalidScheme(String),
|
||||
}
|
||||
|
||||
pub fn get<T>(u: T) -> Result<crate::Response, Error>
|
||||
pub async fn get<T>(u: T, cfg: tokio_rustls::rustls::ClientConfig) -> Result<crate::Response, Error>
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
|
@ -53,38 +41,73 @@ where
|
|||
ur.set_port(Some(1965)).unwrap();
|
||||
}
|
||||
|
||||
if ur.scheme() == "" {
|
||||
let _ = ur.set_scheme("gemini");
|
||||
}
|
||||
|
||||
if ur.scheme() != "gemini" {
|
||||
return Err(Error::InvalidScheme(ur.scheme().to_string()));
|
||||
}
|
||||
|
||||
let cfg = Arc::new(config());
|
||||
let cfg = Arc::new(cfg);
|
||||
let host = ur.host_str().unwrap();
|
||||
let mut sock = TcpStream::connect(&format!("{}:{}", host, ur.port().unwrap()))?;
|
||||
let name_ref = webpki::DNSNameRef::try_from_ascii_str(host)?;
|
||||
let mut client = ClientSession::new(&cfg, name_ref);
|
||||
let mut tls = Stream::new(&mut client, &mut sock);
|
||||
let config = TlsConnector::from(cfg);
|
||||
|
||||
let sock = TcpStream::connect(&format!("{}:{}", host, ur.port().unwrap())).await?;
|
||||
let mut tls = config.connect(name_ref, sock).await?;
|
||||
|
||||
let req = format!("{}\r\n", u);
|
||||
log::trace!("writing request {:?}", req);
|
||||
tls.write(req.as_bytes())?;
|
||||
Ok(Response::parse(&mut tls)?)
|
||||
tls.write(req.as_bytes()).await?;
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
tls.read_to_end(&mut buf).await?;
|
||||
Ok(Response::parse(&mut Cursor::new(buf))?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tokio_rustls::rustls;
|
||||
|
||||
fn config() -> rustls::ClientConfig {
|
||||
let mut config = rustls::ClientConfig::new();
|
||||
config
|
||||
.dangerous()
|
||||
.set_certificate_verifier(Arc::new(NoCertificateVerification {}));
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
struct NoCertificateVerification {}
|
||||
|
||||
impl rustls::ServerCertVerifier for NoCertificateVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_roots: &rustls::RootCertStore,
|
||||
_presented_certs: &[rustls::Certificate],
|
||||
_dns_name: webpki::DNSNameRef<'_>,
|
||||
_ocsp: &[u8],
|
||||
) -> Result<rustls::ServerCertVerified, rustls::TLSError> {
|
||||
Ok(rustls::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
#[test]
|
||||
fn gemini_homepage() -> Result<(), Error> {
|
||||
#[tokio::test]
|
||||
async fn gemini_homepage() -> Result<(), Error> {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
let resp = get("gemini://gemini.circumlunar.space/".to_string())?;
|
||||
let resp = get("gemini://gemini.circumlunar.space/".to_string(), config()).await?;
|
||||
|
||||
assert_eq!(resp.status, StatusCode::Success);
|
||||
assert_eq!(resp.status, crate::StatusCode::Success);
|
||||
assert_eq!(resp.meta, "text/gemini");
|
||||
assert_ne!(resp.body.len(), 0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn gus() -> Result<(), Error> {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
let resp = get("gemini://gus.guru/".to_string(), config()).await?;
|
||||
|
||||
assert_eq!(resp.status, crate::StatusCode::Success);
|
||||
assert_eq!(resp.meta, "text/gemini");
|
||||
assert_ne!(resp.body.len(), 0);
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ impl Response {
|
|||
result.body = data;
|
||||
return Ok(result);
|
||||
}
|
||||
panic!("got here: {}, {:?}", n, state);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue