@@ -5,19 +5,19 @@ use std::sync::Arc;
55use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
66use std:: task:: { Context , Poll } ;
77
8- use zeroize :: Zeroizing ;
8+ use sanitization :: SecretVec ;
99
1010static PHP_REQUEST_BODY_SPOOL_COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1111const PHP_SPOOL_POSITIONAL_READ_BYTES : usize = 64 * 1024 ;
12- type PhpSpoolReadTask = tokio:: task:: JoinHandle < io:: Result < ( Vec < u8 > , usize ) > > ;
12+ type PhpSpoolReadTask = tokio:: task:: JoinHandle < io:: Result < ( SecretVec , usize ) > > ;
1313
1414pub struct PhpRequestBody {
1515 inner : Arc < PhpRequestBodyInner > ,
1616 len : usize ,
1717}
1818
1919enum PhpRequestBodyInner {
20- Memory ( Zeroizing < Vec < u8 > > ) ,
20+ Memory ( Arc < SecretVec > ) ,
2121 Spool ( PhpRequestBodySpool ) ,
2222}
2323
@@ -29,19 +29,25 @@ struct PhpSpoolReader {
2929 file : Arc < std:: fs:: File > ,
3030 offset : u64 ,
3131 pending : Option < PhpSpoolReadTask > ,
32- ready : Vec < u8 > ,
32+ ready : SecretVec ,
3333 ready_start : usize ,
34+ ready_len : usize ,
35+ }
36+
37+ struct PhpMemoryReader {
38+ body : Arc < SecretVec > ,
39+ offset : usize ,
3440}
3541
3642impl PhpRequestBody {
3743 pub fn memory ( body : Vec < u8 > ) -> Self {
38- Self :: memory_zeroizing ( Zeroizing :: new ( body) )
44+ Self :: memory_secret ( SecretVec :: from_vec ( body) )
3945 }
4046
41- pub fn memory_zeroizing ( body : Zeroizing < Vec < u8 > > ) -> Self {
47+ pub fn memory_secret ( body : SecretVec ) -> Self {
4248 Self {
4349 len : body. len ( ) ,
44- inner : Arc :: new ( PhpRequestBodyInner :: Memory ( body) ) ,
50+ inner : Arc :: new ( PhpRequestBodyInner :: Memory ( Arc :: new ( body) ) ) ,
4551 }
4652 }
4753
@@ -67,20 +73,40 @@ impl PhpRequestBody {
6773 & self ,
6874 ) -> io:: Result < Box < dyn fastcgi_client:: io:: AsyncRead + Unpin + Send > > {
6975 match self . inner . as_ref ( ) {
70- PhpRequestBodyInner :: Memory ( body) => {
71- Ok ( Box :: new ( fastcgi_client:: io:: Cursor :: new ( body. clone ( ) ) ) )
72- }
76+ PhpRequestBodyInner :: Memory ( body) => Ok ( Box :: new ( PhpMemoryReader {
77+ body : Arc :: clone ( body) ,
78+ offset : 0 ,
79+ } ) ) ,
7380 PhpRequestBodyInner :: Spool ( spool) => Ok ( Box :: new ( PhpSpoolReader {
7481 file : Arc :: clone ( & spool. file ) ,
7582 offset : 0 ,
7683 pending : None ,
77- ready : Vec :: new ( ) ,
84+ ready : SecretVec :: empty ( ) ,
7885 ready_start : 0 ,
86+ ready_len : 0 ,
7987 } ) ) ,
8088 }
8189 }
8290}
8391
92+ impl fastcgi_client:: io:: AsyncRead for PhpMemoryReader {
93+ fn poll_read (
94+ self : Pin < & mut Self > ,
95+ _context : & mut Context < ' _ > ,
96+ buffer : & mut [ u8 ] ,
97+ ) -> Poll < io:: Result < usize > > {
98+ let this = self . get_mut ( ) ;
99+ let copied = this. body . with_secret ( |body| {
100+ let available = body. get ( this. offset ..) . unwrap_or_default ( ) ;
101+ let copied = available. len ( ) . min ( buffer. len ( ) ) ;
102+ buffer[ ..copied] . copy_from_slice ( & available[ ..copied] ) ;
103+ copied
104+ } ) ;
105+ this. offset = this. offset . saturating_add ( copied) ;
106+ Poll :: Ready ( Ok ( copied) )
107+ }
108+ }
109+
84110impl fastcgi_client:: io:: AsyncRead for PhpSpoolReader {
85111 fn poll_read (
86112 self : Pin < & mut Self > ,
@@ -94,14 +120,18 @@ impl fastcgi_client::io::AsyncRead for PhpSpoolReader {
94120 return Poll :: Ready ( Ok ( 0 ) ) ;
95121 }
96122 loop {
97- if this. ready_start < this. ready . len ( ) {
98- let available = & this. ready [ this. ready_start ..] ;
99- let copied = available. len ( ) . min ( buffer. len ( ) ) ;
100- buffer[ ..copied] . copy_from_slice ( & available[ ..copied] ) ;
123+ if this. ready_start < this. ready_len {
124+ let copied = this. ready . with_secret ( |ready| {
125+ let available = & ready[ this. ready_start ..this. ready_len ] ;
126+ let copied = available. len ( ) . min ( buffer. len ( ) ) ;
127+ buffer[ ..copied] . copy_from_slice ( & available[ ..copied] ) ;
128+ copied
129+ } ) ;
101130 this. ready_start += copied;
102- if this. ready_start == this. ready . len ( ) {
103- this. ready . clear ( ) ;
131+ if this. ready_start == this. ready_len {
132+ this. ready . clear_secret ( ) ;
104133 this. ready_start = 0 ;
134+ this. ready_len = 0 ;
105135 }
106136 return Poll :: Ready ( Ok ( copied) ) ;
107137 }
@@ -135,9 +165,10 @@ impl fastcgi_client::io::AsyncRead for PhpSpoolReader {
135165 } ;
136166 this. offset = next_offset;
137167 this. ready = bytes;
138- this. ready . truncate ( read_len) ;
139168 this. ready_start = 0 ;
169+ this. ready_len = read_len;
140170 if read_len == 0 {
171+ this. ready . clear_secret ( ) ;
141172 return Poll :: Ready ( Ok ( 0 ) ) ;
142173 }
143174 continue ;
@@ -149,8 +180,8 @@ impl fastcgi_client::io::AsyncRead for PhpSpoolReader {
149180 this. pending = Some ( tokio:: task:: spawn_blocking ( move || {
150181 use std:: os:: unix:: fs:: FileExt as _;
151182
152- let mut bytes = vec ! [ 0_u8 ; read_len] ;
153- let read = file. read_at ( & mut bytes, offset) ?;
183+ let mut bytes = SecretVec :: from_fn ( read_len, |_| 0 ) ;
184+ let read = bytes . with_secret_mut ( |bytes| file. read_at ( bytes, offset) ) ?;
154185 Ok ( ( bytes, read) )
155186 } ) ) ;
156187 }
0 commit comments