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
use crate::{_prelude::*, types as rt, types::ExtError};

pub type Result = rt::ExtResult<()>;

pub static REDIRECT_TERM_REASON: &str = "Redirect";
pub static MAX_REDIRECT_TERM_REASON: &str = "MaxRedirect";
pub static CONTENT_TYPE_TERM_REASON: &str = "ContentType";

pub trait Filter<JS: rt::JobStateValues, TS: rt::TaskStateValues> {
	fn name(&self) -> &'static str {
		"no name"
	}
	fn accept(&self, ctx: &mut rt::JobCtx<JS, TS>, task: &rt::Task, status: &rt::HttpStatus) -> Result;
}

pub struct ContentType<'a> {
	accepted: Vec<&'a str>,
}

impl<'a, JS: rt::JobStateValues, TS: rt::TaskStateValues> Filter<JS, TS> for ContentType<'a> {
	name! {}

	fn accept(&self, _ctx: &mut rt::JobCtx<JS, TS>, _task: &rt::Task, status: &rt::HttpStatus) -> Result {
		let content_type = status.headers.get_str(http::header::CONTENT_TYPE)?;
		for accepted in &self.accepted {
			if content_type.contains(accepted) {
				return Ok(())
			}
		}
		Err(rt::ExtError::Term { reason: CONTENT_TYPE_TERM_REASON })
	}
}

impl<'a> ContentType<'a> {
	struct_name! {}

	pub fn new(accepted: Vec<&'a str>) -> Self {
		Self { accepted }
	}
}

pub struct Redirect {
	max_redirects: usize,
}

impl<JS: rt::JobStateValues, TS: rt::TaskStateValues> Filter<JS, TS> for Redirect {
	name! {}

	fn accept(&self, ctx: &mut rt::JobCtx<JS, TS>, task: &rt::Task, status: &rt::HttpStatus) -> Result {
		if !(300..400).contains(&status.code) {
			return Ok(())
		}

		if task.link.redirect >= self.max_redirects {
			return Err(ExtError::Term { reason: MAX_REDIRECT_TERM_REASON })
		}

		let location = status.headers.get_str(http::header::LOCATION)?;

		let mut link = rt::Link::new(location, "", "", "", task.link.redirect + 1, task.link.target, &task.link)
			.context("cannot create link")?;
		link.marker = task.link.marker;

		ctx.push_links(vec![link]);
		Err(ExtError::Term { reason: REDIRECT_TERM_REASON })
	}
}

impl Redirect {
	struct_name! {}

	pub fn new(max_redirects: usize) -> Self {
		Self { max_redirects }
	}
}