diff --git a/proc_macros/proc_macros.rs b/proc_macros/proc_macros.rs index 52c06f0..c64d547 100644 --- a/proc_macros/proc_macros.rs +++ b/proc_macros/proc_macros.rs @@ -209,3 +209,52 @@ pub fn fanbox_api_quick_test(item: TokenStream) -> TokenStream { }; stream.into() } + +struct FilterHttpMethods { + pub req: Ident, + pub typ: Expr, + pub methods: Vec, +} + +impl Parse for FilterHttpMethods { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let req = Ident::parse(input)?; + token::Comma::parse(input)?; + let typ = Expr::parse(input)?; + let mut methods = Vec::new(); + loop { + if input.cursor().eof() { + break; + } + token::Comma::parse(input)?; + let method = Ident::parse(input)?; + methods.push(method); + } + Ok(Self { req, typ, methods }) + } +} + +/// Filter http methods. +/// +/// `request, 405 body, [method [, method [, method ...]]]` +#[proc_macro] +pub fn filter_http_methods(item: TokenStream) -> TokenStream { + let FilterHttpMethods { req, typ, methods } = parse_macro_input!(item as FilterHttpMethods); + let mut header_value = Vec::new(); + let mut streams = Vec::new(); + for method in methods { + header_value.push(method.to_string()); + streams.push(quote!(&hyper::Method::#method => {})); + } + let allow_header = header_value.join(", "); + let allow_header = LitStr::new(allow_header.as_str(), req.span()); + let stream = quote! { + match #req.method() { + #(#streams)* + _ => { + return Ok(hyper::Response::builder().status(405).header("Allow", #allow_header).body(#typ).unwrap()) + } + } + }; + stream.into() +} diff --git a/src/server/service.rs b/src/server/service.rs index da8f5f3..7cf42c8 100644 --- a/src/server/service.rs +++ b/src/server/service.rs @@ -32,6 +32,7 @@ impl Service> for PixivDownloaderSvc { } fn call(&mut self, req: Request) -> Self::Future { + println!("{} {}", req.method(), req.uri()); match self.routes.match_route(&req) { Some(route) => Box::pin(async move { match route.response(req).await { diff --git a/src/server/version.rs b/src/server/version.rs index bbdc9e9..accec88 100644 --- a/src/server/version.rs +++ b/src/server/version.rs @@ -6,6 +6,7 @@ use hyper::Body; use hyper::Request; use hyper::Response; use json::JsonValue; +use proc_macros::filter_http_methods; use regex::Regex; pub struct VersionContext { @@ -22,8 +23,9 @@ impl VersionContext { impl ResponseJsonFor for VersionContext { async fn response_json( &self, - _req: Request, + req: Request, ) -> Result, PixivDownloaderError> { + filter_http_methods!(req, json::object! {}, GET, OPTIONS, POST); Ok(Response::new(json::object! {"version": [0, 0, 1, 0]})) } }