an http based roguelike rpg about jelqing
Blame: src/http/middleware.rs
782069860236 | atagen | 2026-10-10 12:44 UTC | 1 | use std::io::Write as _; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 2 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 3 | use axum::{ |
782069860236 | atagen | 2026-10-10 12:44 UTC | 4 | body::Body, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 5 | extract::Request, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 6 | http::{HeaderValue, StatusCode, Version, header}, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 7 | middleware::Next, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 8 | response::{IntoResponse, Response}, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 9 | }; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 10 | use flate2::{Compression, write::GzEncoder}; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 11 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 12 | use crate::{headers::X_POWERED_BY, problem::Problem}; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 13 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 14 | const MAX_URI: usize = 512; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 15 | const MAX_HEADER: usize = 1024; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 16 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 17 | /// Marks a response for gzip, which the cock ring asks for. |
782069860236 | atagen | 2026-10-10 12:44 UTC | 18 | #[derive(Clone)] |
782069860236 | atagen | 2026-10-10 12:44 UTC | 19 | pub struct Compress; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 20 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 21 | fn reject(request: &Request) -> Option<Problem> { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 22 | if request.version() < Version::HTTP_11 { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 23 | return Some(Problem::new( |
782069860236 | atagen | 2026-10-10 12:44 UTC | 24 | StatusCode::HTTP_VERSION_NOT_SUPPORTED, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 25 | "pdf", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 26 | "HTTP/1.0 is the version the original jelqing PDF was written for. The server has read it.", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 27 | )); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 28 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 29 | if request.uri().to_string().len() > MAX_URI { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 30 | return Some(Problem::new( |
782069860236 | atagen | 2026-10-10 12:44 UTC | 31 | StatusCode::URI_TOO_LONG, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 32 | "uri-too-long", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 33 | "The URI is longer than anything else here.", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 34 | )); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 35 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 36 | if request.headers().values().any(|v| v.len() > MAX_HEADER) { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 37 | return Some(Problem::new( |
782069860236 | atagen | 2026-10-10 12:44 UTC | 38 | StatusCode::REQUEST_HEADER_FIELDS_TOO_LARGE, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 39 | "head-too-large", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 40 | "Head too large.", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 41 | )); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 42 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 43 | let expectation = request.headers().get(header::EXPECT)?; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 44 | if expectation.as_bytes().eq_ignore_ascii_case(b"100-continue") { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 45 | return None; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 46 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 47 | Some(Problem::new( |
782069860236 | atagen | 2026-10-10 12:44 UTC | 48 | StatusCode::EXPECTATION_FAILED, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 49 | "expectations", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 50 | format!( |
782069860236 | atagen | 2026-10-10 12:44 UTC | 51 | "Expect: {} cannot be met.", |
782069860236 | atagen | 2026-10-10 12:44 UTC | 52 | expectation.to_str().unwrap_or("that") |
782069860236 | atagen | 2026-10-10 12:44 UTC | 53 | ), |
782069860236 | atagen | 2026-10-10 12:44 UTC | 54 | )) |
782069860236 | atagen | 2026-10-10 12:44 UTC | 55 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 56 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 57 | async fn compress(response: Response) -> Response { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 58 | let (mut parts, body) = response.into_parts(); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 59 | let Ok(bytes) = axum::body::to_bytes(body, usize::MAX).await else { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 60 | return Response::from_parts(parts, Body::empty()); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 61 | }; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 62 | let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 63 | let gzipped = encoder.write_all(&bytes).and_then(|()| encoder.finish()); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 64 | let Ok(gzipped) = gzipped else { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 65 | return Response::from_parts(parts, Body::from(bytes)); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 66 | }; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 67 | parts |
782069860236 | atagen | 2026-10-10 12:44 UTC | 68 | .headers |
782069860236 | atagen | 2026-10-10 12:44 UTC | 69 | .insert(header::CONTENT_ENCODING, HeaderValue::from_static("gzip")); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 70 | parts.headers.remove(header::CONTENT_LENGTH); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 71 | parts |
782069860236 | atagen | 2026-10-10 12:44 UTC | 72 | .headers |
782069860236 | atagen | 2026-10-10 12:44 UTC | 73 | .append(header::VARY, HeaderValue::from_static("Accept-Encoding")); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 74 | Response::from_parts(parts, Body::from(gzipped)) |
782069860236 | atagen | 2026-10-10 12:44 UTC | 75 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 76 | |
782069860236 | atagen | 2026-10-10 12:44 UTC | 77 | pub async fn chrome(request: Request, next: Next) -> Response { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 78 | let gzip = request |
782069860236 | atagen | 2026-10-10 12:44 UTC | 79 | .headers() |
782069860236 | atagen | 2026-10-10 12:44 UTC | 80 | .get(header::ACCEPT_ENCODING) |
782069860236 | atagen | 2026-10-10 12:44 UTC | 81 | .and_then(|v| v.to_str().ok()) |
782069860236 | atagen | 2026-10-10 12:44 UTC | 82 | .is_some_and(|e| e.to_ascii_lowercase().contains("gzip")); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 83 | let mut response = match reject(&request) { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 84 | Some(problem) => problem.into_response(), |
782069860236 | atagen | 2026-10-10 12:44 UTC | 85 | None => next.run(request).await, |
782069860236 | atagen | 2026-10-10 12:44 UTC | 86 | }; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 87 | if gzip && response.extensions().get::<Compress>().is_some() { |
782069860236 | atagen | 2026-10-10 12:44 UTC | 88 | response = compress(response).await; |
782069860236 | atagen | 2026-10-10 12:44 UTC | 89 | } |
782069860236 | atagen | 2026-10-10 12:44 UTC | 90 | let headers = response.headers_mut(); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 91 | headers.insert(header::SERVER, HeaderValue::from_static("jelqd/0.6.9")); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 92 | headers.insert(X_POWERED_BY, HeaderValue::from_static("blood")); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 93 | headers |
782069860236 | atagen | 2026-10-10 12:44 UTC | 94 | .entry(header::CACHE_CONTROL) |
782069860236 | atagen | 2026-10-10 12:44 UTC | 95 | .or_insert(HeaderValue::from_static("no-store, private")); |
782069860236 | atagen | 2026-10-10 12:44 UTC | 96 | response |
782069860236 | atagen | 2026-10-10 12:44 UTC | 97 | } |