@@ -3,16 +3,16 @@ use crate::{
33 filter:: { is_match_title, is_match_type, TitleFilter } ,
44 rewind:: Rewind ,
55 state:: State ,
6- traffic:: Traffic ,
6+ traffic:: { extract_mime , to_ext_name , Traffic } ,
77} ;
88
99use anyhow:: { anyhow, Context as _, Result } ;
1010use bytes:: Bytes ;
1111use futures_util:: { stream, Sink , SinkExt , Stream , StreamExt , TryStreamExt } ;
1212use http:: {
1313 header:: {
14- CACHE_CONTROL , CONNECTION , CONTENT_DISPOSITION , CONTENT_LENGTH , CONTENT_TYPE ,
15- PROXY_AUTHORIZATION ,
14+ CACHE_CONTROL , CONNECTION , CONTENT_DISPOSITION , CONTENT_ENCODING , CONTENT_LENGTH ,
15+ CONTENT_TYPE , PROXY_AUTHORIZATION ,
1616 } ,
1717 uri:: { Authority , Scheme } ,
1818 HeaderValue ,
@@ -35,7 +35,7 @@ use pin_project_lite::pin_project;
3535use serde:: Serialize ;
3636use std:: {
3737 fs:: File ,
38- io:: Write ,
38+ io:: { Read , Write } ,
3939 path:: PathBuf ,
4040 pin:: Pin ,
4141 process,
@@ -59,7 +59,7 @@ const CERT_INDEX: &str = include_str!("../assets/install-certificate.html");
5959
6060type Request = hyper:: Request < Incoming > ;
6161type Response = hyper:: Response < BoxBody < Bytes , anyhow:: Error > > ;
62- type TrafficDoneSender = mpsc:: UnboundedSender < usize > ;
62+ type TrafficDoneSender = mpsc:: UnboundedSender < ( usize , u64 ) > ;
6363
6464pub struct ServerBuilder {
6565 ca : CertificateAuthority ,
@@ -168,8 +168,8 @@ impl Server {
168168 }
169169 } ) ;
170170 tokio:: spawn ( async move {
171- while let Some ( id ) = traffic_done_rx. recv ( ) . await {
172- self . state . done_traffic ( id) . await ;
171+ while let Some ( ( id , raw_size ) ) = traffic_done_rx. recv ( ) . await {
172+ self . state . done_traffic ( id, raw_size ) . await ;
173173 }
174174 } ) ;
175175 Ok ( stop_tx)
@@ -296,7 +296,8 @@ impl Server {
296296 } else {
297297 None
298298 } ;
299- let req_body = BodyWrapper :: new ( req. into_body ( ) , req_body_file, None ) ;
299+
300+ let req_body = BodyWrapper :: new ( req. into_body ( ) , req_body_file, "" . into ( ) , None ) ;
300301
301302 let proxy_req = match builder. body ( req_body) {
302303 Ok ( v) => v,
@@ -798,7 +799,11 @@ impl Server {
798799
799800 let mut res = Response :: default ( ) ;
800801
802+ let mut encoding = String :: new ( ) ;
801803 for ( key, value) in proxy_res_headers. iter ( ) {
804+ if key == CONTENT_ENCODING {
805+ encoding = value. to_str ( ) . map ( |v| v. to_string ( ) ) . unwrap_or_default ( ) ;
806+ }
802807 res. headers_mut ( ) . insert ( key. clone ( ) , value. clone ( ) ) ;
803808 }
804809
@@ -823,7 +828,8 @@ impl Server {
823828 let res_body = BodyWrapper :: new (
824829 proxy_res. into_body ( ) ,
825830 res_body_file,
826- Some ( ( traffic. id , traffic_done_tx) ) ,
831+ encoding,
832+ Some ( ( traffic. gid , traffic_done_tx) ) ,
827833 ) ;
828834
829835 * res. body_mut ( ) = BoxBody :: new ( res_body) ;
@@ -841,16 +847,18 @@ impl Server {
841847 let mut res = Response :: default ( ) ;
842848 * res. status_mut ( ) = StatusCode :: INTERNAL_SERVER_ERROR ;
843849
844- let traffic_id = traffic. id ;
850+ let gid = traffic. gid ;
845851 traffic. add_error ( error. to_string ( ) ) ;
846852 self . state . add_traffic ( traffic) . await ;
847- self . state . done_traffic ( traffic_id ) . await ;
853+ self . state . done_traffic ( gid , 0 ) . await ;
848854
849855 Ok ( res)
850856 }
851857
852858 fn req_body_file ( & self , traffic : & mut Traffic ) -> Result < File > {
853- let path = self . temp_dir . join ( format ! ( "{}-req" , traffic. id) ) ;
859+ let mime = extract_mime ( & traffic. req_headers ) ;
860+ let ext_name = to_ext_name ( mime) ;
861+ let path = self . temp_dir . join ( format ! ( "{}-req{ext_name}" , traffic. gid) ) ;
854862 let file = File :: create ( & path) . with_context ( || {
855863 format ! (
856864 "Failed to create file '{}' to store request body" ,
@@ -862,7 +870,9 @@ impl Server {
862870 }
863871
864872 fn res_body_file ( & self , traffic : & mut Traffic ) -> Result < File > {
865- let path = self . temp_dir . join ( format ! ( "{}-res" , traffic. id) ) ;
873+ let mime = extract_mime ( & traffic. res_headers ) ;
874+ let ext_name = to_ext_name ( mime) ;
875+ let path = self . temp_dir . join ( format ! ( "{}-res{ext_name}" , traffic. gid) ) ;
866876 let file = File :: create ( & path) . with_context ( || {
867877 format ! (
868878 "Failed to create file '{}' to store response body" ,
@@ -887,12 +897,14 @@ pin_project! {
887897 #[ pin]
888898 inner: B ,
889899 file: Option <File >,
900+ encoding: String ,
890901 traffic_done: Option <( usize , TrafficDoneSender ) >,
902+ raw_size: u64 ,
891903 }
892904 impl <B > PinnedDrop for BodyWrapper <B > {
893905 fn drop( this: Pin <& mut Self >) {
894906 if let Some ( ( id, traffic_done_tx) ) = this. traffic_done. as_ref( ) {
895- let _ = traffic_done_tx. send( * id) ;
907+ let _ = traffic_done_tx. send( ( * id, this . raw_size ) ) ;
896908 }
897909 }
898910 }
@@ -902,12 +914,15 @@ impl<B> BodyWrapper<B> {
902914 pub fn new (
903915 inner : B ,
904916 file : Option < File > ,
917+ encoding : String ,
905918 traffic_done : Option < ( usize , TrafficDoneSender ) > ,
906919 ) -> Self {
907920 Self {
908921 inner,
909922 file,
923+ encoding,
910924 traffic_done,
925+ raw_size : 0 ,
911926 }
912927 }
913928}
@@ -927,9 +942,12 @@ where
927942 match Pin :: new ( & mut this. inner ) . poll_frame ( cx) {
928943 Poll :: Ready ( Some ( Ok ( frame) ) ) => match frame. into_data ( ) {
929944 Ok ( data) => {
930- if let Some ( file) = this. file . as_mut ( ) {
931- let _ = file. write_all ( & data) ;
932- }
945+ if let Ok ( new_data) = decompress ( & data, this. encoding ) {
946+ if let Some ( file) = this. file . as_mut ( ) {
947+ let _ = file. write_all ( & new_data) ;
948+ }
949+ } ;
950+ * this. raw_size += data. len ( ) as u64 ;
933951 Poll :: Ready ( Some ( Ok ( Frame :: data ( data) ) ) )
934952 }
935953 Err ( e) => Poll :: Ready ( Some ( Ok ( e) ) ) ,
@@ -982,3 +1000,33 @@ fn ignore_tungstenite_error(err: &tungstenite::Error) -> bool {
9821000 )
9831001 )
9841002}
1003+
1004+ fn decompress ( data : & [ u8 ] , encoding : & str ) -> Result < Vec < u8 > > {
1005+ match encoding {
1006+ "gzip" => {
1007+ let mut decoder = flate2:: read:: GzDecoder :: new ( data) ;
1008+ let mut decompressed = Vec :: new ( ) ;
1009+ decoder. read_to_end ( & mut decompressed) ?;
1010+ Ok ( decompressed)
1011+ }
1012+ "deflate" => {
1013+ let mut decoder = flate2:: read:: DeflateDecoder :: new ( data) ;
1014+ let mut decompressed = Vec :: new ( ) ;
1015+ decoder. read_to_end ( & mut decompressed) ?;
1016+ Ok ( decompressed)
1017+ }
1018+ "br" => {
1019+ let mut decoder = brotli:: Decompressor :: new ( data, 4096 ) ;
1020+ let mut decompressed = Vec :: new ( ) ;
1021+ decoder. read_to_end ( & mut decompressed) ?;
1022+ Ok ( decompressed)
1023+ }
1024+ "zstd" => {
1025+ let mut decoder = zstd:: stream:: Decoder :: new ( data) ?;
1026+ let mut decompressed = Vec :: new ( ) ;
1027+ decoder. read_to_end ( & mut decompressed) ?;
1028+ Ok ( decompressed)
1029+ }
1030+ _ => Ok ( data. to_vec ( ) ) ,
1031+ }
1032+ }
0 commit comments