1
1
//! rustdoc handler
2
2
3
3
use crate :: {
4
+ RUSTDOC_STATIC_STORAGE_PREFIX ,
4
5
db:: Pool ,
5
6
repositories:: RepositoryStatsUpdater ,
6
- storage:: rustdoc_archive_path,
7
+ storage:: { rustdoc_archive_path, PathNotFoundError } ,
7
8
utils,
8
9
web:: {
9
10
cache:: CachePolicy , crate_details:: CrateDetails , csp:: Csp , error:: Nope , file:: File ,
@@ -766,14 +767,49 @@ pub fn download_handler(req: &mut Request) -> IronResult<Response> {
766
767
) ) )
767
768
}
768
769
770
+ /// Serves shared resources used by rustdoc-generated documentation.
771
+ ///
772
+ /// This serves files from S3, and is pointed to by the `--static-root-path` flag to rustdoc.
773
+ pub fn static_asset_handler ( req : & mut Request ) -> IronResult < Response > {
774
+ let storage = extension ! ( req, Storage ) ;
775
+ let config = extension ! ( req, Config ) ;
776
+
777
+ let filename = req. url . path ( ) [ 2 ..] . join ( "/" ) ;
778
+ let storage_path = format ! ( "{}{}" , RUSTDOC_STATIC_STORAGE_PREFIX , filename) ;
779
+
780
+ // Prevent accessing static files outside the root. This could happen if the path
781
+ // contains `/` or `..`. The check doesn't outright prevent those strings to be present
782
+ // to allow accessing files in subdirectories.
783
+ let canonical_path = std:: fs:: canonicalize ( & storage_path) . map_err ( |_| Nope :: ResourceNotFound ) ?;
784
+ let canonical_root = std:: fs:: canonicalize ( & storage_path) . map_err ( |_| Nope :: ResourceNotFound ) ?;
785
+
786
+ if !canonical_path. starts_with ( canonical_root) {
787
+ return Err ( Nope :: ResourceNotFound . into ( ) ) ;
788
+ }
789
+
790
+ match File :: from_path ( storage, & storage_path, config) {
791
+ Ok ( file) => Ok ( file. serve ( ) ) ,
792
+ Err ( err) if err. downcast_ref :: < PathNotFoundError > ( ) . is_some ( ) => {
793
+ Err ( Nope :: ResourceNotFound . into ( ) )
794
+ }
795
+ Err ( err) => {
796
+ utils:: report_error ( & err) ;
797
+ Err ( Nope :: InternalServerError . into ( ) )
798
+ }
799
+ }
800
+ }
801
+
769
802
/// Serves shared web resources used by rustdoc-generated documentation.
770
803
///
771
804
/// This includes common `css` and `js` files that only change when the compiler is updated, but are
772
805
/// otherwise the same for all crates documented with that compiler. Those have a custom handler to
773
806
/// deduplicate them and save space.
774
- pub struct SharedResourceHandler ;
807
+ ///
808
+ /// This handler considers only the last component of the request path, and looks for a matching file
809
+ /// in the Storage root.
810
+ pub struct LegacySharedResourceHandler ;
775
811
776
- impl Handler for SharedResourceHandler {
812
+ impl Handler for LegacySharedResourceHandler {
777
813
fn handle ( & self , req : & mut Request ) -> IronResult < Response > {
778
814
let path = req. url . path ( ) ;
779
815
let filename = path. last ( ) . unwrap ( ) ; // unwrap is fine: vector is non-empty
@@ -796,6 +832,29 @@ impl Handler for SharedResourceHandler {
796
832
}
797
833
}
798
834
835
+ /// Serves shared web resources used by rustdoc-generated documentation.
836
+ ///
837
+ /// Rustdoc has certain JS, CSS, font and image files that are required for all
838
+ /// documentation it generates, and these don't change often. We make one copy
839
+ /// of these per rustdoc release and serve them from a common location.
840
+ ///
841
+ /// This handler considers the whole path, and looks for a file at that path in
842
+ /// the Storage.
843
+ pub struct SharedResourceHandler ;
844
+
845
+ impl Handler for SharedResourceHandler {
846
+ fn handle ( & self , req : & mut Request ) -> IronResult < Response > {
847
+ let storage = extension ! ( req, Storage ) ;
848
+ let config = extension ! ( req, Config ) ;
849
+
850
+ let storage_path = format ! ( "/{}" , req. url. path( ) . join( "/" ) ) ;
851
+ match File :: from_path ( storage, & storage_path, config) {
852
+ Ok ( file) => Ok ( file. serve ( ) ) ,
853
+ Err ( _) => Err ( Nope :: ResourceNotFound . into ( ) ) ,
854
+ }
855
+ }
856
+ }
857
+
799
858
#[ cfg( test) ]
800
859
mod test {
801
860
use crate :: { test:: * , web:: cache:: CachePolicy , Config } ;
0 commit comments