@@ -14,8 +14,11 @@ use crate::{
1414} ;
1515use anyhow:: { anyhow, Context } ;
1616use iron:: {
17- modifiers:: Redirect , status, url:: percent_encoding:: percent_decode, Handler , IronResult ,
18- Request , Response , Url ,
17+ headers:: { Link , LinkValue , RelationType } ,
18+ modifiers:: Redirect ,
19+ status,
20+ url:: percent_encoding:: percent_decode,
21+ Handler , IronResult , Request , Response , Url ,
1922} ;
2023use lol_html:: errors:: RewritingError ;
2124use once_cell:: sync:: Lazy ;
@@ -243,6 +246,8 @@ impl RustdocPage {
243246 . expect ( "missing Metrics from the request extensions" ) ;
244247
245248 let is_latest_url = self . is_latest_url ;
249+ let canonical_url = self . canonical_url . clone ( ) ;
250+
246251 // Build the page of documentation
247252 let ctx = ctry ! ( req, tera:: Context :: from_serialize( self ) ) ;
248253 let config = extension ! ( req, Config ) ;
@@ -264,6 +269,11 @@ impl RustdocPage {
264269
265270 let mut response = Response :: with ( ( Status :: Ok , html) ) ;
266271 response. headers . set ( ContentType :: html ( ) ) ;
272+ let link_value = LinkValue :: new ( canonical_url)
273+ . push_rel ( RelationType :: ExtRelType ( "canonical" . to_string ( ) ) ) ;
274+
275+ response. headers . set ( Link :: new ( vec ! [ link_value] ) ) ;
276+
267277 response. extensions . insert :: < CachePolicy > ( if is_latest_url {
268278 CachePolicy :: ForeverInCdn
269279 } else {
@@ -2310,31 +2320,45 @@ mod test {
23102320 assert ! ( web
23112321 . get( "/dummy-dash/0.1.0/dummy_dash/" )
23122322 . send( ) ?
2313- . text( ) ?
2323+ . headers( )
2324+ . get( "link" )
2325+ . unwrap( )
2326+ . to_str( )
2327+ . unwrap( )
23142328 . contains( "rel=\" canonical\" " ) , ) ;
23152329
23162330 assert ! ( web
23172331 . get( "/dummy-docs/0.1.0/dummy_docs/" )
23182332 . send( ) ?
2319- . text( ) ?
2320- . contains(
2321- "<link rel=\" canonical\" href=\" https://docs.rs/dummy-docs/latest/dummy_docs/\" />"
2322- ) , ) ;
2333+ . headers( )
2334+ . get( "link" )
2335+ . unwrap( )
2336+ . to_str( )
2337+ . unwrap( )
2338+ . contains( "<https://docs.rs/dummy-docs/latest/dummy_docs/>; rel=\" canonical\" " ) , ) ;
23232339
2324- assert ! (
2325- web
2326- . get( "/dummy-nodocs/0.1.0/dummy_nodocs/" )
2327- . send( ) ?
2328- . text( ) ?
2329- . contains( "<link rel=\" canonical\" href=\" https://docs.rs/dummy-nodocs/latest/dummy_nodocs/\" />" ) ,
2330- ) ;
2340+ assert ! ( web
2341+ . get( "/dummy-nodocs/0.1.0/dummy_nodocs/" )
2342+ . send( ) ?
2343+ . headers( )
2344+ . get( "link" )
2345+ . unwrap( )
2346+ . to_str( )
2347+ . unwrap( )
2348+ . contains(
2349+ "<https://docs.rs/dummy-nodocs/latest/dummy_nodocs/>; rel=\" canonical\" "
2350+ ) , ) ;
23312351
23322352 assert ! (
23332353 web
23342354 . get( "/dummy-nodocs/0.1.0/dummy_nodocs/struct.Foo.html" )
23352355 . send( ) ?
2336- . text( ) ?
2337- . contains( "<link rel=\" canonical\" href=\" https://docs.rs/dummy-nodocs/latest/dummy_nodocs/struct.Foo.html\" />" ) ,
2356+ . headers( )
2357+ . get( "link" )
2358+ . unwrap( )
2359+ . to_str( )
2360+ . unwrap( )
2361+ . contains( "<https://docs.rs/dummy-nodocs/latest/dummy_nodocs/struct.Foo.html>; rel=\" canonical\" " ) ,
23382362 ) ;
23392363 Ok ( ( ) )
23402364 } )
0 commit comments