1use std::{process::ExitStatus, sync::mpsc::Sender};
2
3use crate::{exec, pkgx::Pkgx, Extension};
4use anyhow::Error;
5use fluentci_types::Output;
6
7#[derive(Default)]
8pub struct Http {}
9
10impl Http {
11 pub fn validate_url(&self, url: &str) -> Result<(), Error> {
12 if url.is_empty() {
13 return Err(Error::msg("URL is empty"));
14 }
15 if !regex::Regex::new(r"^(http|https)://[^ ]+$")
16 .unwrap()
17 .is_match(url)
18 {
19 return Err(Error::msg("Invalid URL"));
20 }
21 Ok(())
22 }
23}
24
25impl Extension for Http {
26 fn exec(
27 &mut self,
28 url: &str,
29 tx: Sender<String>,
30 out: Output,
31 last_cmd: bool,
32 work_dir: &str,
33 ) -> Result<ExitStatus, Error> {
34 self.setup()?;
35 if self.validate_url(url).is_err() {
36 return Err(Error::msg("Invalid URL"));
37 }
38
39 let filename = sha256::digest(url).to_string();
40
41 let cmd = format!("curl -s {} -o {}", url, filename);
42 exec(&cmd, tx, out, last_cmd, work_dir)
43 }
44
45 fn setup(&self) -> Result<(), Error> {
46 Pkgx::default().install(vec!["curl"])?;
47 Ok(())
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn test_validate_url() {
57 let http = Http::default();
58 assert!(http.validate_url("https://example.com").is_ok());
59 assert!(http.validate_url("http://example.com").is_ok());
60 assert!(http.validate_url("http://example.com/").is_ok());
61 assert!(http.validate_url("http://example.com/path").is_ok());
62 assert!(http.validate_url("http://example.com/path?query").is_ok());
63 assert!(http
64 .validate_url("http://example.com/path?query#fragment")
65 .is_ok());
66 assert!(http
67 .validate_url("example.com/path?query#fragment")
68 .is_err());
69 assert!(http.validate_url("ftp://example.com").is_err());
70 }
71}