aboutsummaryrefslogtreecommitdiff
path: root/src/modules/finger.rs
blob: 34140c007c5f6c842dc6766133583188bf914e67 (plain) (blame)
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
use {
  crate::{response::success, route::track_mount},
  std::{
    io::{Read, Write},
    time::Duration,
  },
  windmark::response::Response,
};

pub fn module(router: &mut windmark::router::Router) {
  track_mount(router, "/finger", "Finger-to-Gemini Gateway", |context| {
    success(
      &format!(
        r"# Finger-to-Gemini Gateway

To use this gateway, simply append the address of your target resource to the end of the current route, minus the protocol. Routed paths are supported!

To visit my personal Finger server, <finger://fuwn.me>, you would visit <gemini://fuwn.me/finger/fuwn.me>.

=> /finger/fuwn.me Try it!"
      ),
      &context,
    )
  });
  track_mount(
    router,
    "/finger/*uri",
    "-Finger-to-Gemini Gateway Router",
    |context| {
      if let Some(uri) = context.parameters.get("uri") {
        let path;
        let url = url::Url::parse({
          let mut parts = uri.split("/");
          let host = parts.next().unwrap();

          path = parts.collect::<Vec<&str>>().join("/");

          &if !host.contains(":") {
            format!("{}:79", host)
          } else {
            host.to_string()
          }
        })
        .unwrap();

        let mut stream = std::net::TcpStream::connect(url.to_string()).unwrap();
        let mut buffer = [0; 1024];

        stream
          .set_read_timeout(Some(Duration::from_secs(5)))
          .expect("error: set_read_timeout failed");
        stream
          .set_write_timeout(Some(Duration::from_secs(5)))
          .expect("error: set_write_timeout failed");
        stream.write_all(format!("{path}\n").as_bytes()).unwrap();

        let mut response = String::new();

        loop {
          let bytes_read = match stream.read(&mut buffer) {
            Ok(0) => break,
            Ok(n) => n,
            Err(e) => {
              eprintln!("error: failed to read from socket: {:?}", e);

              break;
            }
          };

          #[allow(unsafe_code)]
          response.push_str(unsafe {
            std::str::from_utf8_unchecked(&buffer[..bytes_read])
          });
        }

        Response::success(response)
      } else {
        Response::bad_request("Invalid URI")
      }
    },
  );
}