@@ -124,7 +124,7 @@ use base64::Engine as _;
124124use bytes:: Bytes ;
125125use futures_util:: StreamExt ;
126126use objectstore_metrics:: TimerGuard ;
127- use objectstore_types:: metadata:: Metadata ;
127+ use objectstore_types:: metadata:: { ExpirationPolicy , Metadata } ;
128128use objectstore_types:: range:: ByteRange ;
129129use objectstore_types:: resumable:: UploadProgress ;
130130use objectstore_types:: time:: Timestamp ;
@@ -490,10 +490,11 @@ type LongTermBackendToken = BackendToken;
490490struct TieredResumableToken {
491491 inner : LongTermBackendToken ,
492492 revision : String ,
493- /// Duration of a time-based expiration policy , applied from the commit time.
493+ /// Expiration policy requested for the object , applied from the commit time.
494494 ///
495- /// `None` for manual expiration.
496- expires_in : Option < Duration > ,
495+ /// Required, so tokens issued before this field existed fail to decode instead of
496+ /// committing without an expiry.
497+ expiration_policy : ExpirationPolicy ,
497498}
498499
499500impl TieredResumableToken {
@@ -582,7 +583,7 @@ impl Backend for TieredStorage {
582583 let token = TieredResumableToken {
583584 revision : revision. key ,
584585 inner,
585- expires_in : metadata. expiration_policy . expires_in ( ) ,
586+ expiration_policy : metadata. expiration_policy ,
586587 } ;
587588 Ok ( Some ( serde_json:: to_string ( & token) . context (
588589 ErrorKind :: Internal ,
@@ -605,7 +606,7 @@ impl Backend for TieredStorage {
605606 backend_type = self . backend_type( & BackendChoice :: LongTerm ) ,
606607 ) ;
607608 let tiered = TieredResumableToken :: decode ( & session. backend_token ) ?;
608- let expires_in = tiered. expires_in ;
609+ let expires_in = tiered. expiration_policy . expires_in ( ) ;
609610 let inner_session = tiered. into_inner_session ( session) ;
610611 let id = & session. object_id ;
611612 let revision = & inner_session. object_id ;
@@ -1807,6 +1808,17 @@ mod tests {
18071808 Ok ( ( ) )
18081809 }
18091810
1811+ #[ test]
1812+ fn resumable_token_requires_expiration_policy ( ) {
1813+ let legacy = r#"{"inner":"token","revision":"key/rev","time_expires":null}"# ;
1814+ assert_eq ! (
1815+ TieredResumableToken :: decode( & legacy. to_owned( ) )
1816+ . unwrap_err( )
1817+ . kind( ) ,
1818+ ErrorKind :: UnknownUploadSession
1819+ ) ;
1820+ }
1821+
18101822 #[ tokio:: test]
18111823 async fn resumable_commit_requires_confirmed_expiry ( ) {
18121824 let ( storage, hv, _, events) = tiered_with_expiry_hooks ( false , true ) ;
0 commit comments