11use anyhow:: { bail, Result } ;
22use base64:: { engine:: general_purpose:: STANDARD , Engine as _} ;
3- use serde:: Serialize ;
3+ use serde:: { Serialize , Serializer } ;
44use serde_json:: { json, Value } ;
5+ use time:: { format_description:: well_known:: Rfc3339 , OffsetDateTime } ;
56
67const HEX_VIEW_SIZE : usize = 320 ;
78
89#[ derive( Debug , Clone , Serialize ) ]
910pub struct Traffic {
1011 pub uri : String ,
1112 pub method : String ,
13+ #[ serde( serialize_with = "serialize_datetime" ) ]
14+ pub start : OffsetDateTime ,
1215 pub req_version : Option < String > ,
1316 pub req_headers : Option < Headers > ,
1417 pub req_body : Option < Body > ,
@@ -24,6 +27,7 @@ impl Traffic {
2427 Self {
2528 uri : uri. to_string ( ) ,
2629 method : method. to_string ( ) ,
30+ start : OffsetDateTime :: now_utc ( ) ,
2731 req_version : None ,
2832 req_headers : None ,
2933 req_body : None ,
@@ -90,7 +94,7 @@ impl Traffic {
9094 "cookies" : har_req_cookies( & self . req_headers) ,
9195 "headers" : har_headers( & self . req_headers) ,
9296 "queryString" : har_query_string( & self . uri) ,
93- "postData" : har_body ( & self . req_body, & self . req_headers) ,
97+ "postData" : har_req_body ( & self . req_body, & self . req_headers) ,
9498 "headersSize" : -1 ,
9599 "bodySize" : -1 ,
96100 } ) ;
@@ -101,7 +105,7 @@ impl Traffic {
101105 "httpVersion" : self . res_version,
102106 "cookies" : har_res_cookies( & self . res_headers) ,
103107 "headers" : har_headers( & self . res_headers) ,
104- "content" : har_body ( & self . res_body, & self . res_headers) ,
108+ "content" : har_res_body ( & self . res_body, & self . res_headers) ,
105109 "redirectURL" : get_header_value( & self . res_headers, "location" ) . unwrap_or_default( ) ,
106110 "headersSize" : -1 ,
107111 "bodySize" : -1 ,
@@ -119,8 +123,18 @@ impl Traffic {
119123 "pages" : [ ] ,
120124 "entries" : [
121125 {
126+ "startedDateTime" : self . start. format( & Rfc3339 ) . unwrap_or_default( ) ,
127+ "time" : -1 ,
122128 "request" : request,
123- "response" : response
129+ "response" : response,
130+ "cache" : { } ,
131+ "timings" : {
132+ "connect" : -1 ,
133+ "ssl" : -1 ,
134+ "send" : -1 ,
135+ "receive" : -1 ,
136+ "wait" : -1
137+ }
124138 }
125139 ]
126140 }
@@ -332,17 +346,25 @@ fn har_req_cookies(headers: &Option<Headers>) -> Value {
332346 }
333347}
334348
335- fn har_body ( body : & Option < Body > , headers : & Option < Headers > ) -> Value {
349+ fn har_req_body ( body : & Option < Body > , headers : & Option < Headers > ) -> Value {
350+ let content_type = get_header_value ( headers, "content-type" ) . unwrap_or_default ( ) ;
351+ match body {
352+ Some ( body) => json ! ( { "mimeType" : content_type, "text" : body. value} ) ,
353+ None => json ! ( { "mimeType" : content_type, "text" : "" } ) ,
354+ }
355+ }
356+
357+ fn har_res_body ( body : & Option < Body > , headers : & Option < Headers > ) -> Value {
336358 let content_type = get_header_value ( headers, "content-type" ) . unwrap_or_default ( ) ;
337359 match body {
338360 Some ( body) => {
339- let mut value = json ! ( { "mimeType" : content_type, "text" : body. value} ) ;
361+ let mut value = json ! ( { "mimeType" : content_type, "text" : body. value, "size" : - 1 } ) ;
340362 if !body. is_utf8 ( ) {
341363 value[ "encoding" ] = "base64" . into ( ) ;
342364 }
343365 value
344366 }
345- None => json ! ( { "mimeType" : content_type, "text" : "" } ) ,
367+ None => json ! ( { "mimeType" : content_type, "text" : "" , "size" : 0 } ) ,
346368 }
347369}
348370
@@ -412,15 +434,25 @@ fn md_lang(content_type: &str) -> &str {
412434 }
413435}
414436
437+ fn serialize_datetime < S > ( date : & OffsetDateTime , serializer : S ) -> Result < S :: Ok , S :: Error >
438+ where
439+ S : Serializer ,
440+ {
441+ let formatted = date. format ( & Rfc3339 ) . map_err ( serde:: ser:: Error :: custom) ?;
442+ serializer. serialize_str ( & formatted)
443+ }
444+
415445#[ cfg( test) ]
416446mod tests {
417447 use super :: * ;
418448 use pretty_assertions:: assert_eq;
449+ use time:: format_description:: well_known:: Rfc3339 ;
419450
420451 fn create_traffic1 ( ) -> Traffic {
421452 Traffic {
422453 uri : "http://example.com/?q1=3" . to_string ( ) ,
423454 method : "PUT" . to_string ( ) ,
455+ start : OffsetDateTime :: parse ( "2024-03-14T03:48:34.821Z" , & Rfc3339 ) . unwrap ( ) ,
424456 req_version : None ,
425457 req_headers : Some ( vec ! [
426458 Header :: new( "content-type" , "plain/text" ) ,
@@ -506,6 +538,8 @@ ERROR: error"#;
506538 "pages": [],
507539 "entries": [
508540 {
541+ "startedDateTime": "2024-03-14T03:48:34.821Z",
542+ "time": -1,
509543 "request": {
510544 "method": "PUT",
511545 "url": "http://example.com/?q1=3",
@@ -587,11 +621,20 @@ ERROR: error"#;
587621 ],
588622 "content": {
589623 "mimeType": "application/json; charset=utf-8",
590- "text": "{\"message\":\"OK\"}"
624+ "text": "{\"message\":\"OK\"}",
625+ "size": -1
591626 },
592627 "redirectURL": "",
593628 "headersSize": -1,
594629 "bodySize": -1
630+ },
631+ "cache": {},
632+ "timings": {
633+ "connect": -1,
634+ "ssl": -1,
635+ "send": -1,
636+ "receive": -1,
637+ "wait": -1
595638 }
596639 }
597640 ]
0 commit comments