@@ -2,17 +2,23 @@ import {getHeader} from "../../helpers/har";
2
2
import { Entry , Header } from "../../typing/har" ;
3
3
import { WaterfallEntry } from "../../typing/waterfall" ;
4
4
5
- function parseAndFormat < S , T > ( source : S , parseFn : ( ( _ : S ) => T ) , formatFn : ( ( _ : T ) => string ) ) : string {
6
- if ( typeof source === "undefined" ) {
5
+ function parseAndFormat < S , T > ( source ?: S ,
6
+ parseFn : ( ( _ : S ) => T ) = identity ,
7
+ formatFn : ( ( _ : T ) => string ) = identity ) : string {
8
+ if ( source === undefined ) {
7
9
return undefined ;
8
10
}
9
11
const parsed = parseFn ( source ) ;
10
- if ( typeof parsed === " undefined" ) {
12
+ if ( parsed === undefined ) {
11
13
return undefined ;
12
14
}
13
15
return formatFn ( parsed ) ;
14
16
}
15
17
18
+ function identity < T > ( source : T ) : T {
19
+ return source ;
20
+ }
21
+
16
22
function parseDate ( s : string ) : Date {
17
23
const date = new Date ( s ) ;
18
24
if ( isNaN ( date . getTime ( ) ) ) {
@@ -21,11 +27,27 @@ function parseDate(s: string): Date {
21
27
return date ;
22
28
}
23
29
24
- function parseNonNegative ( n : number ) : number {
25
- if ( n < 0 ) {
26
- return undefined ;
30
+ function parseNonNegative ( input : string | number ) : number {
31
+ const criteria = ( n : number ) => ( n < 0 ) ;
32
+ return parseToNumber ( input , criteria ) ;
33
+ }
34
+
35
+ function parsePositive ( input : string | number ) : number {
36
+ const criteria = ( n : number ) => ( n <= 0 ) ;
37
+ return parseToNumber ( input , criteria ) ;
38
+ }
39
+
40
+ function parseToNumber ( input : string | number , criteria : ( _ : number ) => boolean ) : number {
41
+ const parse = ( n : number ) => criteria ( n ) ? undefined : n ;
42
+
43
+ if ( typeof input === "string" ) {
44
+ const n = parseInt ( input , 10 ) ;
45
+ if ( ! isFinite ( n ) ) {
46
+ return undefined ;
47
+ }
48
+ return parse ( n ) ;
27
49
}
28
- return n ;
50
+ return parse ( input ) ;
29
51
}
30
52
31
53
function formatMilliseconds ( millis : number ) : string {
@@ -36,31 +58,15 @@ function formatDateLocalized(d: Date): string {
36
58
return `${ d . toUTCString ( ) } </br>(local time: ${ d . toLocaleString ( ) } )` ;
37
59
}
38
60
39
- let ifValueDefined = ( value : number , fn : ( _ : number ) => any ) => {
40
- if ( ! isFinite ( value ) || value <= 0 ) {
41
- return undefined ;
42
- }
43
- return fn ( value ) ;
44
- } ;
45
-
46
- let formatBytes = ( size ?: number ) => ifValueDefined ( size , ( s ) => `${ s } byte (~${ Math . round ( s / 1024 * 10 ) / 10 } kb)` ) ;
47
-
48
- let asIntPartial = ( val : string , ifIntFn : ( _ : number ) => any ) => {
49
- let v = parseInt ( val , 10 ) ;
50
- return ifValueDefined ( v , ifIntFn ) ;
51
- } ;
61
+ function formatBytes ( size : number ) : string {
62
+ return `${ size } byte (~${ Math . round ( size / 1024 * 10 ) / 10 } kb)` ;
63
+ }
52
64
53
65
/** get experimental feature (usually WebPageTest) */
54
66
let getExp = ( harEntry : Entry , name : string ) : string => {
55
67
return harEntry [ name ] || harEntry [ "_" + name ] || harEntry . request [ name ] || harEntry . request [ "_" + name ] || "" ;
56
68
} ;
57
69
58
- /** get experimental feature and ensure it's not a sting of `0` or `` */
59
- let getExpNotNull = ( harEntry : Entry , name : string ) : string => {
60
- let resp = getExp ( harEntry , name ) ;
61
- return resp !== "0" ? resp : "" ;
62
- } ;
63
-
64
70
/** get experimental feature and format it as byte */
65
71
let getExpAsByte = ( harEntry : Entry , name : string ) : string => {
66
72
let resp = parseInt ( getExp ( harEntry , name ) , 10 ) ;
@@ -72,7 +78,7 @@ function parseGeneralDetails(entry: WaterfallEntry, requestID: number): KvTuple[
72
78
return [
73
79
[ "Request Number" , `#${ requestID } ` ] ,
74
80
[ "Started" , new Date ( harEntry . startedDateTime ) . toLocaleString ( ) + ( ( entry . start > 0 ) ?
75
- " (" + formatMilliseconds ( entry . start ) + " after page request started)" : "" ) ] ,
81
+ " (" + formatMilliseconds ( entry . start ) + " after page request started)" : "" ) ] ,
76
82
[ "Duration" , formatMilliseconds ( harEntry . time ) ] ,
77
83
[ "Error/Status Code" , harEntry . response . status + " " + harEntry . response . statusText ] ,
78
84
[ "Server IPAddress" , harEntry . serverIPAddress ] ,
@@ -83,14 +89,14 @@ function parseGeneralDetails(entry: WaterfallEntry, requestID: number): KvTuple[
83
89
[ "Initiator Line" , harEntry . _initiator_line ] ,
84
90
[ "Host" , getHeader ( harEntry . request . headers , "Host" ) ] ,
85
91
[ "IP" , harEntry . _ip_addr ] ,
86
- [ "Client Port" , harEntry . _client_port ] ,
92
+ [ "Client Port" , parseAndFormat ( harEntry . _client_port , parsePositive ) ] ,
87
93
[ "Expires" , harEntry . _expires ] ,
88
- [ "Cache Time" , harEntry . _cache_time ] ,
94
+ [ "Cache Time" , parseAndFormat ( harEntry . _cache_time , parsePositive ) ] ,
89
95
[ "CDN Provider" , harEntry . _cdn_provider ] ,
90
- [ "ObjectSize" , harEntry . _objectSize ] ,
96
+ [ "ObjectSize" , parseAndFormat ( harEntry . _objectSize , parsePositive , formatBytes ) ] ,
91
97
[ "Bytes In (downloaded)" , getExpAsByte ( harEntry , "bytesIn" ) ] ,
92
98
[ "Bytes Out (uploaded)" , getExpAsByte ( harEntry , "bytesOut" ) ] ,
93
- [ "JPEG Scan Count" , getExpNotNull ( harEntry , "jpeg_scan_count" ) ] ,
99
+ [ "JPEG Scan Count" , parseAndFormat ( harEntry . _jpeg_scan_count , parsePositive ) ] ,
94
100
[ "Gzip Total" , getExpAsByte ( harEntry , "gzip_total" ) ] ,
95
101
[ "Gzip Save" , getExpAsByte ( harEntry , "gzip_save" ) ] ,
96
102
[ "Minify Total" , getExpAsByte ( harEntry , "minify_total" ) ] ,
@@ -109,8 +115,8 @@ function parseRequestDetails(harEntry: Entry): KvTuple[] {
109
115
[ "Method" , request . method ] ,
110
116
[ "HTTP Version" , request . httpVersion ] ,
111
117
[ "Bytes Out (uploaded)" , getExpAsByte ( harEntry , "bytesOut" ) ] ,
112
- [ "Headers Size" , formatBytes ( request . headersSize ) ] ,
113
- [ "Body Size" , formatBytes ( request . bodySize ) ] ,
118
+ [ "Headers Size" , parseAndFormat ( request . headersSize , parseNonNegative , formatBytes ) ] ,
119
+ [ "Body Size" , parseAndFormat ( request . bodySize , parseNonNegative , formatBytes ) ] ,
114
120
[ "Comment" , request . comment ] ,
115
121
stringHeader ( "User-Agent" ) ,
116
122
stringHeader ( "Host" ) ,
@@ -122,7 +128,7 @@ function parseRequestDetails(harEntry: Entry): KvTuple[] {
122
128
stringHeader ( "If-Modified-Since" ) ,
123
129
stringHeader ( "If-Range" ) ,
124
130
stringHeader ( "If-Unmodified-Since" ) ,
125
- [ "Querystring parameters count" , request . queryString . length ] ,
131
+ [ "Querystring parameters count" , parseAndFormat ( request . queryString . length , parsePositive ) ] ,
126
132
[ "Cookies count" , request . cookies . length ] ,
127
133
] ;
128
134
}
@@ -149,17 +155,17 @@ function parseResponseDetails(harEntry: Entry): KvTuple[] {
149
155
[ "Status" , response . status + " " + response . statusText ] ,
150
156
[ "HTTP Version" , response . httpVersion ] ,
151
157
[ "Bytes In (downloaded)" , getExpAsByte ( harEntry , "bytesIn" ) ] ,
152
- [ "Header Size" , formatBytes ( response . headersSize ) ] ,
153
- [ "Body Size" , formatBytes ( response . bodySize ) ] ,
158
+ [ "Headers Size" , parseAndFormat ( response . headersSize , parseNonNegative , formatBytes ) ] ,
159
+ [ "Body Size" , parseAndFormat ( response . bodySize , parseNonNegative , formatBytes ) ] ,
154
160
[ "Content-Type" , contentType ] ,
155
161
stringHeader ( "Cache-Control" ) ,
156
162
stringHeader ( "Content-Encoding" ) ,
157
163
dateHeader ( "Expires" ) ,
158
164
dateHeader ( "Last-Modified" ) ,
159
165
stringHeader ( "Pragma" ) ,
160
- [ "Content-Length" , asIntPartial ( contentLength , formatBytes ) ] ,
166
+ [ "Content-Length" , parseAndFormat ( contentLength , parseNonNegative , formatBytes ) ] ,
161
167
[ "Content Size" , ( contentLength !== content . size . toString ( ) ? formatBytes ( content . size ) : "" ) ] ,
162
- [ "Content Compression" , formatBytes ( content . compression ) ] ,
168
+ [ "Content Compression" , parseAndFormat ( content . compression , parsePositive , formatBytes ) ] ,
163
169
stringHeader ( "Connection" ) ,
164
170
stringHeader ( "ETag" ) ,
165
171
stringHeader ( "Accept-Patch" ) ,
0 commit comments