|
1 |
| -use crate::{db::Pool, docbuilder::Limits, impl_webpage, web::page::WebPage}; |
| 1 | +use crate::{db::Pool, docbuilder::Limits, impl_webpage, web::error::Nope, web::page::WebPage}; |
2 | 2 | use chrono::{DateTime, NaiveDateTime, Utc};
|
3 | 3 | use iron::{
|
4 | 4 | headers::ContentType,
|
@@ -40,7 +40,15 @@ impl_webpage! {
|
40 | 40 |
|
41 | 41 | pub fn sitemap_handler(req: &mut Request) -> IronResult<Response> {
|
42 | 42 | let router = extension!(req, Router);
|
43 |
| - let letter = cexpect!(req, router.find("letter")).to_lowercase(); |
| 43 | + let letter = cexpect!(req, router.find("letter")); |
| 44 | + |
| 45 | + if letter.len() != 1 { |
| 46 | + return Err(Nope::ResourceNotFound.into()); |
| 47 | + } else if let Some(ch) = letter.chars().next() { |
| 48 | + if !(ch.is_ascii_lowercase()) { |
| 49 | + return Err(Nope::ResourceNotFound.into()); |
| 50 | + } |
| 51 | + } |
44 | 52 |
|
45 | 53 | let mut conn = extension!(req, Pool).get()?;
|
46 | 54 | let query = conn
|
@@ -156,21 +164,72 @@ pub fn about_handler(req: &mut Request) -> IronResult<Response> {
|
156 | 164 | #[cfg(test)]
|
157 | 165 | mod tests {
|
158 | 166 | use crate::test::{assert_success, wrapper};
|
| 167 | + use reqwest::StatusCode; |
| 168 | + |
| 169 | + #[test] |
| 170 | + fn sitemap_index() { |
| 171 | + wrapper(|env| { |
| 172 | + let web = env.frontend(); |
| 173 | + assert_success("/sitemap.xml", web) |
| 174 | + }) |
| 175 | + } |
| 176 | + |
| 177 | + #[test] |
| 178 | + fn sitemap_invalid_letters() { |
| 179 | + wrapper(|env| { |
| 180 | + let web = env.frontend(); |
| 181 | + |
| 182 | + // everything not length=1 and ascii-lowercase should fail |
| 183 | + for invalid_letter in &["1", "aa", "A", ""] { |
| 184 | + println!("trying to fail letter {}", invalid_letter); |
| 185 | + assert_eq!( |
| 186 | + web.get(&format!("/-/sitemap/{}/sitemap.xml", invalid_letter)) |
| 187 | + .send()? |
| 188 | + .status(), |
| 189 | + StatusCode::NOT_FOUND |
| 190 | + ); |
| 191 | + } |
| 192 | + Ok(()) |
| 193 | + }) |
| 194 | + } |
159 | 195 |
|
160 | 196 | #[test]
|
161 |
| - fn sitemap() { |
| 197 | + fn sitemap_letter() { |
162 | 198 | wrapper(|env| {
|
163 | 199 | let web = env.frontend();
|
164 |
| - assert_success("/sitemap.xml", web)?; |
165 |
| - assert_success("/-/sitemap/s/sitemap.xml", web)?; |
| 200 | + |
| 201 | + let letters: Vec<char> = (b'a'..=b'z').map(char::from).collect(); |
| 202 | + |
| 203 | + // letter-sitemaps always work, even without crates & releases |
| 204 | + for letter in letters.iter().as_ref() { |
| 205 | + assert_success(&format!("/-/sitemap/{}/sitemap.xml", letter), web)?; |
| 206 | + } |
166 | 207 |
|
167 | 208 | env.fake_release().name("some_random_crate").create()?;
|
168 | 209 | env.fake_release()
|
169 | 210 | .name("some_random_crate_that_failed")
|
170 | 211 | .build_result_successful(false)
|
171 | 212 | .create()?;
|
172 |
| - assert_success("/sitemap.xml", web)?; |
173 |
| - assert_success("/-/sitemap/s/sitemap.xml", web) |
| 213 | + |
| 214 | + // these fake crates appear only in the `s` sitemap |
| 215 | + let response = web.get("/-/sitemap/s/sitemap.xml").send()?; |
| 216 | + assert!(response.status().is_success()); |
| 217 | + |
| 218 | + let content = response.text()?; |
| 219 | + assert!(content.contains(&"some_random_crate")); |
| 220 | + assert!(!(content.contains(&"some_random_crate_that_failed"))); |
| 221 | + |
| 222 | + // and not in the others |
| 223 | + for letter in letters.iter().filter(|&&c| c != 's') { |
| 224 | + let response = web |
| 225 | + .get(&format!("/-/sitemap/{}/sitemap.xml", letter)) |
| 226 | + .send()?; |
| 227 | + |
| 228 | + assert!(response.status().is_success()); |
| 229 | + assert!(!(response.text()?.contains("some_random_crate"))); |
| 230 | + } |
| 231 | + |
| 232 | + Ok(()) |
174 | 233 | })
|
175 | 234 | }
|
176 | 235 |
|
|
0 commit comments