w3c_validators/w3c_validators/
css_validator.rs1extern crate serde_json;
2
3use std::default::Default;
4use std::time::Duration;
5
6use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
7use reqwest::multipart::Form as MultipartForm;
8use reqwest::Client as HttpClient;
9use reqwest::{Response, StatusCode};
10
11pub const CSS_VALIDATOR_URI: &str = "https://jigsaw.w3.org/css-validator/validator";
12
13#[derive(Serialize, Deserialize)]
14pub struct CssResult {
15 pub errorcount: u8,
16 pub warningcount: u8,
17}
18
19#[derive(Serialize, Deserialize)]
20pub struct CssValidation {
21 pub uri: String,
22 pub checkedby: String,
23 pub csslevel: String,
24 pub date: String,
25 pub timestamp: String,
26 pub validity: bool,
27 pub result: CssResult,
28 pub warnings: Option<Vec<Message>>,
29 pub errors: Option<Vec<Message>>,
30}
31
32#[derive(Serialize, Deserialize)]
33pub struct Message {
34 pub source: String,
35 pub message: String,
36 pub line: u8,
37 #[serde(rename = "type")]
38 pub _type: String,
39 pub level: Option<u8>,
40}
41
42#[derive(Serialize, Deserialize)]
43pub struct CssValidatorResult {
44 pub cssvalidation: CssValidation,
45}
46
47pub struct CssValidatorOpts {
48 validator_uri: String,
49}
50
51impl CssValidation {
52 pub fn is_valid(&self) -> bool {
53 match self.errors {
54 Some(ref err) => err.is_empty(),
55 None => true,
56 }
57 }
58}
59
60impl CssValidatorResult {
61 pub fn is_valid(&self) -> bool {
62 self.cssvalidation.is_valid()
63 }
64}
65
66impl Default for CssValidatorOpts {
67 fn default() -> CssValidatorOpts {
68 CssValidatorOpts {
69 validator_uri: CSS_VALIDATOR_URI.to_string(),
70 }
71 }
72}
73
74pub struct CssValidator {
75 pub validator_uri: String,
76 http_client: HttpClient,
77}
78
79impl CssValidator {
97 pub fn new(opts: CssValidatorOpts) -> CssValidator {
98 let http_client = HttpClient::builder()
99 .timeout(Duration::from_secs(5))
100 .build()
101 .expect("HttpClient failed to construct");
102 CssValidator {
103 validator_uri: opts.validator_uri,
104 http_client,
105 }
106 }
107
108 fn fetch_result(&self, mut response: Response) -> Option<CssValidatorResult> {
109 match response.text() {
110 Ok(data) => match serde_json::from_str(&data) {
111 Ok(v) => Some(v),
112 _ => None,
113 },
114 _ => None,
115 }
116 }
117
118 pub fn validate_uri(&self, uri: &str) -> Option<CssValidatorResult> {
119 let url = &format!("{}?uri={}&output=json", CSS_VALIDATOR_URI, uri);
120 match self
121 .http_client
122 .get(url)
123 .header(USER_AGENT, ua_validator!())
124 .send()
125 {
126 Err(_) => None,
127 Ok(response) => match response.status() {
128 StatusCode::OK | StatusCode::NOT_MODIFIED => self.fetch_result(response),
129 _ => None,
130 },
131 }
132 }
133
134 pub fn validate_text(&self, text: &'static str) -> Option<CssValidatorResult> {
135 let mut headers = HeaderMap::new();
136 headers.insert(USER_AGENT, HeaderValue::from_static(ua_validator!()));
137 let form = MultipartForm::new()
138 .text("text", text)
139 .text("output", "json");
140 match self
141 .http_client
142 .post(CSS_VALIDATOR_URI)
143 .multipart(form)
144 .headers(headers)
145 .send()
146 {
147 Err(_) => None,
148 Ok(response) => match response.status() {
149 StatusCode::OK | StatusCode::NOT_MODIFIED => self.fetch_result(response),
150 _ => None,
151 },
152 }
153 }
154}