@@ -237,7 +237,8 @@ impl APSPackedEncoder {
237237 } else {
238238 // search in tag cache
239239 if let Some ( existing) = self . key_table . get_buf_idx ( & attribute. id ) {
240- self . write_tagged_value ( 5 , existing as u64 , 0x20 | flags, writer) ?;
240+ info ! ( "Using kcache {existing}" ) ;
241+ writer. write_all ( & [ 0x20 | flags | existing as u8 ] ) ?;
241242 } else {
242243 self . write_tagged_value ( 4 , attribute. id . len ( ) as u64 - 1 , 0x10 | flags, writer) ?;
243244
@@ -248,6 +249,7 @@ impl APSPackedEncoder {
248249
249250 // actually write the value
250251 if let Some ( existing) = existing {
252+ info ! ( "Using vcache {existing}" ) ;
251253 self . write_tagged_value ( 8 , existing as u64 , 0 , writer) ?;
252254 } else if let Some ( cached_buf) = cached_buf {
253255 writer. write_all ( & cached_buf) ?;
@@ -945,6 +947,148 @@ impl APSMessage {
945947}
946948
947949
950+ #[ tokio:: test]
951+ async fn replay_test ( ) {
952+ use keystore:: { init_keystore, software:: { SoftwareKeystore , NoEncryptor } } ;
953+ init_keystore ( SoftwareKeystore {
954+ state : plist:: from_file ( "jerrytest/keystore.plist" ) . unwrap ( ) ,
955+ update_state : Box :: new ( |state| {
956+ plist:: to_file_xml ( "jerrytest/keystore.plist" , state) . unwrap ( ) ;
957+ } ) ,
958+ encryptor : NoEncryptor ,
959+ } ) ;
960+
961+ if let Err ( _) = std:: env:: var ( "RUST_LOG" ) {
962+ std:: env:: set_var ( "RUST_LOG" , "debug" ) ;
963+ }
964+ let _ = pretty_env_logger:: try_init ( ) ;
965+
966+ let state_path = std:: env:: var ( "APS_REPLAY_STATE" )
967+ . unwrap_or_else ( |_| if std:: path:: Path :: new ( "jerrytest/push.plist" ) . exists ( ) {
968+ "jerrytest/push.plist" . to_string ( )
969+ } else {
970+ "jerrytest/push.plist" . to_string ( )
971+ } ) ;
972+ let log_path = std:: env:: var ( "APS_REPLAY_LOG" )
973+ . unwrap_or_else ( |_| if std:: path:: Path :: new ( "jerrytest/replaytest.log" ) . exists ( ) {
974+ "jerrytest/replaytest.log" . to_string ( )
975+ } else {
976+ "jerrytest/replaytest.log" . to_string ( )
977+ } ) ;
978+
979+ let mut state: APSState = plist:: from_file ( & state_path) . unwrap ( ) ;
980+ let pair = state. keypair . as_ref ( ) . expect ( "replay APS state must already contain a keypair" ) ;
981+
982+ let ( socket, encoder, mut decoder) = open_socket ( ) . await . unwrap ( ) ;
983+ let ( mut read, write) = split ( socket) ;
984+ let ( send, _) = tokio:: sync:: broadcast:: channel ( 999 ) ;
985+ let socket = Arc :: new ( DebugMutex :: new ( Some ( ( write, encoder) ) ) ) ;
986+
987+ let reader_send = send. clone ( ) ;
988+ let mut reader = task:: spawn ( async move {
989+ loop {
990+ match APSMessage :: read_from_stream ( & mut read, & mut decoder) . await {
991+ Ok ( Some ( msg) ) => {
992+ let _ = reader_send. send ( msg) ;
993+ } ,
994+ Ok ( None ) => { } ,
995+ Err ( err) => {
996+ return Err ( err) ;
997+ }
998+ } ;
999+ }
1000+
1001+ #[ allow( unreachable_code) ]
1002+ Ok :: < ( ) , PushError > ( ( ) )
1003+ } ) ;
1004+
1005+ let nonce = generate_nonce ( NonceType :: APNS ) ;
1006+ let signature = do_ids_signature ( & pair. private , & nonce) . unwrap ( ) ;
1007+ let mut recv = send. subscribe ( ) ;
1008+ replay_send ( & socket, APSMessage :: Connect {
1009+ flags : 0b01000001 ,
1010+ certificate : Some ( pair. cert . clone ( ) ) ,
1011+ nonce : Some ( nonce) ,
1012+ signature : Some ( signature) ,
1013+ token : state. token ,
1014+ } ) . await . unwrap ( ) ;
1015+
1016+ let ( token, status) = tokio:: time:: timeout ( Duration :: from_secs ( 15 ) , async {
1017+ loop {
1018+ if let APSMessage :: ConnectResponse { token, status } = recv. recv ( ) . await . unwrap ( ) {
1019+ return ( token, status) ;
1020+ }
1021+ }
1022+ } ) . await . unwrap ( ) ;
1023+
1024+ assert_eq ! ( status, 0 , "APS connect failed with status {status}" ) ;
1025+ if let Some ( token) = token {
1026+ state. token = Some ( token) ;
1027+ }
1028+
1029+ let replay = std:: fs:: read_to_string ( & log_path) . unwrap ( ) ;
1030+ let mut sent = 0usize ;
1031+ let mut skipped_first_send = false ;
1032+ for ( line_index, line) in replay. lines ( ) . enumerate ( ) {
1033+ let Some ( ( _, rest) ) = line. split_once ( "Sending \" " ) else {
1034+ continue ;
1035+ } ;
1036+ if !skipped_first_send {
1037+ skipped_first_send = true ;
1038+ continue ;
1039+ }
1040+ if sent >= 0 {
1041+ break ;
1042+ }
1043+ let Some ( ( hex, _) ) = rest. split_once ( '"' ) else {
1044+ panic ! ( "bad Sending line {}: missing closing quote" , line_index + 1 ) ;
1045+ } ;
1046+ info ! ( "Sending {}" , sent + 1 ) ;
1047+ let bytes = decode_hex ( hex) . unwrap ( ) ;
1048+ let message: APSMessage = plist:: from_bytes ( & bytes) . unwrap ( ) ;
1049+ replay_send ( & socket, message) . await . unwrap ( ) ;
1050+ sent += 1 ;
1051+ }
1052+
1053+ assert ! ( skipped_first_send, "no Sending lines found in {log_path}" ) ;
1054+ info ! ( "replayed {sent} APS messages from {log_path}" ) ;
1055+
1056+ tokio:: select! {
1057+ result = & mut reader => {
1058+ match result {
1059+ Ok ( Ok ( ( ) ) ) => panic!( "replay APS reader ended before observation window ended" ) ,
1060+ Ok ( Err ( err) ) => panic!( "replay APS reader stopped before observation window ended: {err}" ) ,
1061+ Err ( err) => panic!( "replay APS reader task failed before observation window ended: {err}" ) ,
1062+ }
1063+ }
1064+ _ = tokio:: time:: sleep( Duration :: from_secs( 5 ) ) => { }
1065+ }
1066+
1067+ reader. abort ( ) ;
1068+ }
1069+
1070+ #[ cfg( test) ]
1071+ async fn replay_send (
1072+ socket : & DebugMutex < Option < ( WriteHalf < TlsStream < TcpStream > > , Option < APSPackedEncoder > ) > > ,
1073+ message : APSMessage ,
1074+ ) -> Result < ( ) , PushError > {
1075+ let mut socket_guard = socket. lock ( ) . await ;
1076+ let socket = socket_guard. as_mut ( ) . ok_or ( PushError :: NotConnected ) ?;
1077+ if let Some ( encoder) = & mut socket. 1 {
1078+ let mut buf = vec ! [ ] ;
1079+ encoder. encode_message ( message. to_packed_raw ( ) , Cursor :: new ( & mut buf) ) ?;
1080+ socket. 0 . write_all ( & buf) . await ?;
1081+ } else {
1082+ let mut raw = message. to_raw ( ) ;
1083+ for message in & mut raw. body {
1084+ message. update ( ) ?;
1085+ }
1086+ raw. update ( ) ?;
1087+ socket. 0 . write_all ( & raw . to_bytes ( ) ?) . await ?;
1088+ }
1089+ Ok ( ( ) )
1090+ }
1091+
9481092#[ tokio:: test]
9491093async fn proxy ( ) {
9501094 if let Err ( _) = std:: env:: var ( "RUST_LOG" ) {
@@ -1092,11 +1236,16 @@ async fn open_socket() -> Result<(TlsStream<TcpStream>, Option<APSPackedEncoder>
10921236 if let Some ( protocol) = stream. get_ref ( ) . 1 . alpn_protocol ( ) {
10931237 let protocol = std:: str:: from_utf8 ( protocol) . unwrap ( ) ;
10941238 if protocol. starts_with ( "apns-pack-v1" ) {
1095- let mut parts = protocol. split ( ":" ) ;
1096- let encoder_count: usize = parts. nth ( 1 ) . expect ( "Bad ALPN1!" ) . parse ( ) . expect ( "Bad alpn3!" ) ;
1097- let decoder_count: usize = parts. next ( ) . expect ( "Bad ALPN2!" ) . parse ( ) . expect ( "Bad alpn4!" ) ;
1098- encoder = Some ( APSPackedEncoder :: new_with_cache_size ( encoder_count) ) ;
1099- decoder = Some ( APSPackedDecoder :: new_with_cache_size ( decoder_count) ) ;
1239+ if protocol. contains ( ":" ) {
1240+ let mut parts = protocol. split ( ":" ) ;
1241+ let encoder_count: usize = parts. nth ( 1 ) . expect ( "Bad ALPN1!" ) . parse ( ) . expect ( "Bad alpn3!" ) ;
1242+ let decoder_count: usize = parts. next ( ) . expect ( "Bad ALPN2!" ) . parse ( ) . expect ( "Bad alpn4!" ) ;
1243+ encoder = Some ( APSPackedEncoder :: new_with_cache_size ( encoder_count) ) ;
1244+ decoder = Some ( APSPackedDecoder :: new_with_cache_size ( decoder_count) ) ;
1245+ } else {
1246+ encoder = Some ( APSPackedEncoder :: default ( ) ) ;
1247+ decoder = Some ( APSPackedDecoder :: default ( ) ) ;
1248+ }
11001249 }
11011250 }
11021251
@@ -1387,7 +1536,8 @@ impl APSConnectionResource {
13871536
13881537 let mut buf = vec ! [ ] ;
13891538 encoder. encode_message ( message. to_packed_raw ( ) , Cursor :: new ( & mut buf) ) ?;
1390-
1539+
1540+ debug ! ( "Sendin2g {:?}" , encode_hex( & buf) ) ;
13911541 socket. 0 . write_all ( & buf) . await
13921542 } else {
13931543 let mut raw = message. to_raw ( ) ;
0 commit comments