@@ -157,7 +157,7 @@ mod content_range {
157157
158158#[ cfg( test) ]
159159mod range {
160- use crate :: headers:: { OrderedRange , range:: HttpRange } ;
160+ use crate :: headers:: { OrderedRange , ParseHttpRangeOrContentRangeError , range:: HttpRange } ;
161161
162162 #[ test]
163163 fn succesful_starting_parsing ( ) {
@@ -200,4 +200,348 @@ mod range {
200200 fn succesful_suffix_to_string ( ) {
201201 assert_eq ! ( "bytes=-100" , & HttpRange :: Suffix ( 100 ) . to_string( ) ) ;
202202 }
203+
204+ #[ test]
205+ fn empty_input ( ) {
206+ assert_eq ! (
207+ "" . parse:: <HttpRange >( ) . unwrap_err( ) ,
208+ ParseHttpRangeOrContentRangeError :: Empty
209+ ) ;
210+ }
211+
212+ #[ test]
213+ fn whitespace_only_input ( ) {
214+ assert_eq ! (
215+ " " . parse:: <HttpRange >( ) . unwrap_err( ) ,
216+ ParseHttpRangeOrContentRangeError :: Empty
217+ ) ;
218+ }
219+
220+ #[ test]
221+ fn missing_equals ( ) {
222+ assert_eq ! (
223+ "bytes50-100" . parse:: <HttpRange >( ) . unwrap_err( ) ,
224+ ParseHttpRangeOrContentRangeError :: Malformed
225+ ) ;
226+ }
227+
228+ #[ test]
229+ fn wrong_unit ( ) {
230+ assert_eq ! (
231+ "items=0-10" . parse:: <HttpRange >( ) . unwrap_err( ) ,
232+ ParseHttpRangeOrContentRangeError :: InvalidUnit
233+ ) ;
234+ }
235+
236+ #[ test]
237+ fn both_empty ( ) {
238+ assert_eq ! (
239+ "bytes=-" . parse:: <HttpRange >( ) . unwrap_err( ) ,
240+ ParseHttpRangeOrContentRangeError :: Malformed
241+ ) ;
242+ }
243+
244+ #[ test]
245+ fn unordered_range ( ) {
246+ assert ! ( "bytes=100-50" . parse:: <HttpRange >( ) . is_err( ) ) ;
247+ }
248+
249+ #[ test]
250+ fn plus_prefix_rejected_in_starting_point ( ) {
251+ assert ! ( "bytes=+50-" . parse:: <HttpRange >( ) . is_err( ) ) ;
252+ }
253+
254+ #[ test]
255+ fn plus_prefix_rejected_in_suffix ( ) {
256+ assert ! ( "bytes=-+100" . parse:: <HttpRange >( ) . is_err( ) ) ;
257+ }
258+
259+ #[ test]
260+ fn plus_prefix_rejected_in_range ( ) {
261+ assert ! ( "bytes=+50-100" . parse:: <HttpRange >( ) . is_err( ) ) ;
262+ assert ! ( "bytes=50-+100" . parse:: <HttpRange >( ) . is_err( ) ) ;
263+ }
264+
265+ #[ test]
266+ fn multi_range_rejected ( ) {
267+ assert ! ( "bytes=0-50, 100-150" . parse:: <HttpRange >( ) . is_err( ) ) ;
268+ }
269+
270+ #[ test]
271+ fn suffix_zero_parsing ( ) {
272+ assert_eq ! (
273+ "bytes=-0" . parse:: <HttpRange >( ) . unwrap( ) ,
274+ HttpRange :: Suffix ( 0 )
275+ ) ;
276+ }
277+
278+ #[ test]
279+ fn starting_point_zero ( ) {
280+ assert_eq ! (
281+ "bytes=0-" . parse:: <HttpRange >( ) . unwrap( ) ,
282+ HttpRange :: StartingPoint ( 0 )
283+ ) ;
284+ }
285+
286+ #[ test]
287+ fn range_single_byte ( ) {
288+ assert_eq ! (
289+ "bytes=0-0" . parse:: <HttpRange >( ) . unwrap( ) ,
290+ HttpRange :: Range ( OrderedRange :: new( 0 ..=0 ) . unwrap( ) )
291+ ) ;
292+ }
293+ }
294+
295+ #[ cfg( test) ]
296+ mod content_range_parsing_errors {
297+ use crate :: headers:: { ParseHttpRangeOrContentRangeError , content_range:: HttpContentRange } ;
298+
299+ #[ test]
300+ fn empty_input ( ) {
301+ assert_eq ! (
302+ "" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
303+ ParseHttpRangeOrContentRangeError :: Empty
304+ ) ;
305+ }
306+
307+ #[ test]
308+ fn missing_space ( ) {
309+ assert_eq ! (
310+ "bytes10-20/50" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
311+ ParseHttpRangeOrContentRangeError :: Malformed
312+ ) ;
313+ }
314+
315+ #[ test]
316+ fn wrong_unit ( ) {
317+ assert_eq ! (
318+ "items 10-20/50" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
319+ ParseHttpRangeOrContentRangeError :: InvalidUnit
320+ ) ;
321+ }
322+
323+ #[ test]
324+ fn missing_slash ( ) {
325+ assert_eq ! (
326+ "bytes 10-20" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
327+ ParseHttpRangeOrContentRangeError :: Malformed
328+ ) ;
329+ }
330+
331+ #[ test]
332+ fn star_star ( ) {
333+ assert_eq ! (
334+ "bytes */*" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
335+ ParseHttpRangeOrContentRangeError :: Malformed
336+ ) ;
337+ }
338+
339+ #[ test]
340+ fn end_exceeds_size ( ) {
341+ assert_eq ! (
342+ "bytes 10-20/15" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
343+ ParseHttpRangeOrContentRangeError :: MalformedRange
344+ ) ;
345+ }
346+
347+ #[ test]
348+ fn end_equals_size ( ) {
349+ assert_eq ! (
350+ "bytes 0-20/20" . parse:: <HttpContentRange >( ) . unwrap_err( ) ,
351+ ParseHttpRangeOrContentRangeError :: MalformedRange
352+ ) ;
353+ }
354+
355+ #[ test]
356+ fn end_at_boundary ( ) {
357+ assert ! ( "bytes 0-19/20" . parse:: <HttpContentRange >( ) . is_ok( ) ) ;
358+ }
359+ }
360+
361+ #[ cfg( test) ]
362+ mod file_range {
363+ use std:: num:: NonZeroU64 ;
364+
365+ use crate :: {
366+ file_range,
367+ headers:: {
368+ OrderedRange ,
369+ content_range:: { Bound , HttpContentRange } ,
370+ range:: HttpRange ,
371+ } ,
372+ } ;
373+
374+ fn size ( n : u64 ) -> NonZeroU64 {
375+ NonZeroU64 :: new ( n) . unwrap ( )
376+ }
377+
378+ #[ test]
379+ fn no_range_returns_full_file ( ) {
380+ let result = file_range ( size ( 10 ) , None ) . unwrap ( ) ;
381+ assert ! ( result. header( ) . is_none( ) ) ;
382+ assert_eq ! ( result. range( ) , & ( 0 ..=9 ) ) ;
383+ }
384+
385+ #[ test]
386+ fn starting_point_zero ( ) {
387+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: StartingPoint ( 0 ) ) ) . unwrap ( ) ;
388+ assert ! ( result. header( ) . is_some( ) ) ;
389+ assert_eq ! ( result. range( ) , & ( 0 ..=9 ) ) ;
390+ }
391+
392+ #[ test]
393+ fn starting_point_middle ( ) {
394+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: StartingPoint ( 5 ) ) ) . unwrap ( ) ;
395+ assert_eq ! ( result. range( ) , & ( 5 ..=9 ) ) ;
396+ }
397+
398+ #[ test]
399+ fn starting_point_last_byte ( ) {
400+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: StartingPoint ( 9 ) ) ) . unwrap ( ) ;
401+ assert_eq ! ( result. range( ) , & ( 9 ..=9 ) ) ;
402+ }
403+
404+ #[ test]
405+ fn starting_point_at_size ( ) {
406+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: StartingPoint ( 10 ) ) ) ;
407+ assert ! ( result. is_err( ) ) ;
408+ }
409+
410+ #[ test]
411+ fn starting_point_beyond_size ( ) {
412+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: StartingPoint ( 20 ) ) ) ;
413+ assert ! ( result. is_err( ) ) ;
414+ }
415+
416+ #[ test]
417+ fn range_single_byte ( ) {
418+ let range = HttpRange :: Range ( OrderedRange :: new ( 0 ..=0 ) . unwrap ( ) ) ;
419+ let result = file_range ( size ( 10 ) , Some ( range) ) . unwrap ( ) ;
420+ assert_eq ! ( result. range( ) , & ( 0 ..=0 ) ) ;
421+ }
422+
423+ #[ test]
424+ fn range_full_file ( ) {
425+ let range = HttpRange :: Range ( OrderedRange :: new ( 0 ..=9 ) . unwrap ( ) ) ;
426+ let result = file_range ( size ( 10 ) , Some ( range) ) . unwrap ( ) ;
427+ assert_eq ! ( result. range( ) , & ( 0 ..=9 ) ) ;
428+ }
429+
430+ #[ test]
431+ fn range_end_at_size ( ) {
432+ let range = HttpRange :: Range ( OrderedRange :: new ( 0 ..=10 ) . unwrap ( ) ) ;
433+ let result = file_range ( size ( 10 ) , Some ( range) ) ;
434+ assert ! ( result. is_err( ) ) ;
435+ }
436+
437+ #[ test]
438+ fn range_beyond_size ( ) {
439+ let range = HttpRange :: Range ( OrderedRange :: new ( 0 ..=50 ) . unwrap ( ) ) ;
440+ let result = file_range ( size ( 10 ) , Some ( range) ) ;
441+ assert ! ( result. is_err( ) ) ;
442+ }
443+
444+ #[ test]
445+ fn suffix_entire_file ( ) {
446+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: Suffix ( 10 ) ) ) . unwrap ( ) ;
447+ assert_eq ! ( result. range( ) , & ( 0 ..=9 ) ) ;
448+ }
449+
450+ #[ test]
451+ fn suffix_last_byte ( ) {
452+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: Suffix ( 1 ) ) ) . unwrap ( ) ;
453+ assert_eq ! ( result. range( ) , & ( 9 ..=9 ) ) ;
454+ }
455+
456+ #[ test]
457+ fn suffix_middle ( ) {
458+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: Suffix ( 5 ) ) ) . unwrap ( ) ;
459+ assert_eq ! ( result. range( ) , & ( 5 ..=9 ) ) ;
460+ }
461+
462+ #[ test]
463+ fn suffix_zero_is_unsatisfiable ( ) {
464+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: Suffix ( 0 ) ) ) ;
465+ assert ! ( result. is_err( ) ) ;
466+ }
467+
468+ #[ test]
469+ fn suffix_exceeds_size ( ) {
470+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: Suffix ( 11 ) ) ) ;
471+ assert ! ( result. is_err( ) ) ;
472+ }
473+
474+ #[ test]
475+ fn size_one_no_range ( ) {
476+ let result = file_range ( size ( 1 ) , None ) . unwrap ( ) ;
477+ assert_eq ! ( result. range( ) , & ( 0 ..=0 ) ) ;
478+ }
479+
480+ #[ test]
481+ fn size_one_starting_point_zero ( ) {
482+ let result = file_range ( size ( 1 ) , Some ( HttpRange :: StartingPoint ( 0 ) ) ) . unwrap ( ) ;
483+ assert_eq ! ( result. range( ) , & ( 0 ..=0 ) ) ;
484+ }
485+
486+ #[ test]
487+ fn size_one_suffix_one ( ) {
488+ let result = file_range ( size ( 1 ) , Some ( HttpRange :: Suffix ( 1 ) ) ) . unwrap ( ) ;
489+ assert_eq ! ( result. range( ) , & ( 0 ..=0 ) ) ;
490+ }
491+
492+ #[ test]
493+ fn content_range_header_present_for_range_request ( ) {
494+ let result = file_range ( size ( 10 ) , Some ( HttpRange :: StartingPoint ( 0 ) ) ) . unwrap ( ) ;
495+ let header = result. header ( ) . unwrap ( ) ;
496+ assert_eq ! (
497+ header,
498+ HttpContentRange :: Bound ( Bound :: new( 0 ..=9 , Some ( 10 ) ) . unwrap( ) )
499+ ) ;
500+ }
501+ }
502+
503+ #[ cfg( test) ]
504+ mod serve_file {
505+ use bytes:: Bytes ;
506+
507+ use crate :: { headers:: range:: HttpRange , serve_file_with_http_range} ;
508+
509+ #[ test]
510+ fn no_range_returns_full_body ( ) {
511+ let body = Bytes :: from_static ( b"hello world" ) ;
512+ let result = serve_file_with_http_range ( body. clone ( ) , None ) . unwrap ( ) ;
513+ assert_eq ! ( result. body( ) , & body) ;
514+ assert ! ( result. header( ) . is_none( ) ) ;
515+ }
516+
517+ #[ test]
518+ fn range_slices_body ( ) {
519+ let body = Bytes :: from_static ( b"hello world" ) ;
520+ let range = Some ( HttpRange :: StartingPoint ( 6 ) ) ;
521+ let result = serve_file_with_http_range ( body, range) . unwrap ( ) ;
522+ assert_eq ! ( result. body( ) , & Bytes :: from_static( b"world" ) ) ;
523+ assert ! ( result. header( ) . is_some( ) ) ;
524+ }
525+
526+ #[ test]
527+ fn suffix_slices_from_end ( ) {
528+ let body = Bytes :: from_static ( b"hello world" ) ;
529+ let range = Some ( HttpRange :: Suffix ( 5 ) ) ;
530+ let result = serve_file_with_http_range ( body, range) . unwrap ( ) ;
531+ assert_eq ! ( result. body( ) , & Bytes :: from_static( b"world" ) ) ;
532+ }
533+
534+ #[ test]
535+ fn empty_body_is_unsatisfiable ( ) {
536+ let body = Bytes :: new ( ) ;
537+ let result = serve_file_with_http_range ( body, None ) ;
538+ assert ! ( result. is_err( ) ) ;
539+ }
540+
541+ #[ test]
542+ fn suffix_zero_is_unsatisfiable ( ) {
543+ let body = Bytes :: from_static ( b"hello" ) ;
544+ let result = serve_file_with_http_range ( body, Some ( HttpRange :: Suffix ( 0 ) ) ) ;
545+ assert ! ( result. is_err( ) ) ;
546+ }
203547}
0 commit comments