@@ -11,19 +11,24 @@ use axum::{
1111 response:: { IntoResponse , Response as AxumResponse } ,
1212} ;
1313use http:: header:: CONTENT_LENGTH ;
14- use iron:: { headers:: ContentType , response:: Response , status:: Status , IronResult , Request } ;
14+ use iron:: {
15+ headers:: { ContentType , Link , LinkValue , RelationType } ,
16+ response:: Response ,
17+ status:: Status ,
18+ IronResult , Request ,
19+ } ;
1520use serde:: Serialize ;
1621use std:: { borrow:: Cow , sync:: Arc } ;
1722use tera:: { Context , Tera } ;
1823
1924/// When making using a custom status, use a closure that coerces to a `fn(&Self) -> Status`
2025#[ macro_export]
2126macro_rules! impl_webpage {
22- ( $page: ty = $template: literal $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , ) ?) => {
23- $crate:: impl_webpage!( $page = |_| :: std:: borrow:: Cow :: Borrowed ( $template) $( , status = $status) ? $( , content_type = $content_type) ?) ;
27+ ( $page: ty = $template: literal $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $ ( , canonical_url = $canonical_url : expr ) ? $( , ) ?) => {
28+ $crate:: impl_webpage!( $page = |_| :: std:: borrow:: Cow :: Borrowed ( $template) $( , status = $status) ? $( , content_type = $content_type) ? $ ( , canonical_url = $canonical_url ) ? ) ;
2429 } ;
2530
26- ( $page: ty = $template: expr $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , ) ?) => {
31+ ( $page: ty = $template: expr $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , canonical_url = $canonical_url : expr ) ? $ ( , ) ?) => {
2732 impl $crate:: web:: page:: WebPage for $page {
2833 fn template( & self ) -> :: std:: borrow:: Cow <' static , str > {
2934 let template: fn ( & Self ) -> :: std:: borrow:: Cow <' static , str > = $template;
@@ -37,6 +42,14 @@ macro_rules! impl_webpage {
3742 }
3843 ) ?
3944
45+
46+ $(
47+ fn canonical_url( & self ) -> Option <String > {
48+ let canonical_url: fn ( & Self ) -> Option <String > = $canonical_url;
49+ ( canonical_url) ( self )
50+ }
51+ ) ?
52+
4053 $(
4154 fn content_type( ) -> :: iron:: headers:: ContentType {
4255 $content_type
@@ -48,11 +61,11 @@ macro_rules! impl_webpage {
4861
4962#[ macro_export]
5063macro_rules! impl_axum_webpage {
51- ( $page: ty = $template: literal $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , ) ?) => {
52- $crate:: impl_axum_webpage!( $page = |_| :: std:: borrow:: Cow :: Borrowed ( $template) $( , status = $status) ? $( , content_type = $content_type) ?) ;
64+ ( $page: ty = $template: literal $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , canonical_url = $canonical_url : expr ) ? $ ( , ) ?) => {
65+ $crate:: impl_axum_webpage!( $page = |_| :: std:: borrow:: Cow :: Borrowed ( $template) $( , status = $status) ? $( , content_type = $content_type) ? $ ( , canonical_url = $canonical_url : expr ) ? ) ;
5366 } ;
5467
55- ( $page: ty = $template: expr $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , ) ?) => {
68+ ( $page: ty = $template: expr $( , status = $status: expr) ? $( , content_type = $content_type: expr) ? $( , canonical_url = $canonical_url : expr ) ? $ ( , ) ?) => {
5669 impl axum:: response:: IntoResponse for $page
5770 {
5871 fn into_response( self ) -> :: axum:: response:: Response {
@@ -134,12 +147,24 @@ pub trait WebPage: Serialize + Sized {
134147 response. extensions . insert :: < CachePolicy > ( cache) ;
135148 }
136149
150+ if let Some ( canonical_url) = self . canonical_url ( ) {
151+ let link_value = LinkValue :: new ( canonical_url)
152+ . push_rel ( RelationType :: ExtRelType ( "canonical" . to_string ( ) ) ) ;
153+
154+ response. headers . set ( Link :: new ( vec ! [ link_value] ) ) ;
155+ }
156+
137157 Ok ( response)
138158 }
139159
140160 /// The name of the template to be rendered
141161 fn template ( & self ) -> Cow < ' static , str > ;
142162
163+ /// The canonical URL to set in response headers
164+ fn canonical_url ( & self ) -> Option < String > {
165+ None
166+ }
167+
143168 /// Gets the status of the request, defaults to `Ok`
144169 fn get_status ( & self ) -> Status {
145170 Status :: Ok
0 commit comments