@@ -868,7 +868,27 @@ pub(crate) fn chunked_stream(
868
868
}
869
869
870
870
pub ( crate ) fn read_range ( file : & mut File , path : & PathBuf , range : Range < u64 > ) -> Result < Bytes > {
871
- let to_read = range. end - range. start ;
871
+ let file_metadata = file. metadata ( ) . map_err ( |e| Error :: Metadata {
872
+ source : e. into ( ) ,
873
+ path : path. to_string_lossy ( ) . to_string ( ) ,
874
+ } ) ?;
875
+
876
+ // If none of the range is satisfiable we should error, e.g. if the start offset is beyond the
877
+ // extents of the file
878
+ let file_len = file_metadata. len ( ) ;
879
+ if range. start >= file_len {
880
+ return Err ( Error :: InvalidRange {
881
+ source : InvalidGetRange :: StartTooLarge {
882
+ requested : range. start ,
883
+ length : file_len,
884
+ } ,
885
+ }
886
+ . into ( ) ) ;
887
+ }
888
+
889
+ // Don't read past end of file
890
+ let to_read = range. end . min ( file_len) - range. start ;
891
+
872
892
file. seek ( SeekFrom :: Start ( range. start ) ) . map_err ( |source| {
873
893
let path = path. into ( ) ;
874
894
Error :: Seek { source, path }
@@ -1131,6 +1151,44 @@ mod tests {
1131
1151
assert_eq ! ( & * read_data, data) ;
1132
1152
}
1133
1153
1154
+ #[ tokio:: test]
1155
+ async fn range_request_start_beyond_end_of_file ( ) {
1156
+ let root = TempDir :: new ( ) . unwrap ( ) ;
1157
+ let integration = LocalFileSystem :: new_with_prefix ( root. path ( ) ) . unwrap ( ) ;
1158
+
1159
+ let location = Path :: from ( "some_file" ) ;
1160
+
1161
+ let data = Bytes :: from ( "arbitrary data" ) ;
1162
+
1163
+ integration
1164
+ . put ( & location, data. clone ( ) . into ( ) )
1165
+ . await
1166
+ . unwrap ( ) ;
1167
+
1168
+ integration
1169
+ . get_range ( & location, 100 ..200 )
1170
+ . await
1171
+ . expect_err ( "Should error with start range beyond end of file" ) ;
1172
+ }
1173
+
1174
+ #[ tokio:: test]
1175
+ async fn range_request_beyond_end_of_file ( ) {
1176
+ let root = TempDir :: new ( ) . unwrap ( ) ;
1177
+ let integration = LocalFileSystem :: new_with_prefix ( root. path ( ) ) . unwrap ( ) ;
1178
+
1179
+ let location = Path :: from ( "some_file" ) ;
1180
+
1181
+ let data = Bytes :: from ( "arbitrary data" ) ;
1182
+
1183
+ integration
1184
+ . put ( & location, data. clone ( ) . into ( ) )
1185
+ . await
1186
+ . unwrap ( ) ;
1187
+
1188
+ let read_data = integration. get_range ( & location, 0 ..100 ) . await . unwrap ( ) ;
1189
+ assert_eq ! ( & * read_data, data) ;
1190
+ }
1191
+
1134
1192
#[ tokio:: test]
1135
1193
#[ cfg( target_family = "unix" ) ]
1136
1194
// Fails on github actions runner (which runs the tests as root)
0 commit comments