UNPKG

12.6 kBPlain TextView Raw
1// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/* eslint-disable @typescript-eslint/no-explicit-any */
6
7class HARBase {
8 readonly custom: Map<string, any>;
9 constructor(data: any) {
10 if (!data || typeof data !== 'object') {
11 throw 'First parameter is expected to be an object';
12 }
13 this.custom = new Map();
14 }
15
16 static safeDate(data: any): Date {
17 const date = new Date(data);
18 if (!Number.isNaN(date.getTime())) {
19 return date;
20 }
21 throw 'Invalid date format';
22 }
23
24 static safeNumber(data: any): number {
25 const result = Number(data);
26 if (!Number.isNaN(result)) {
27 return result;
28 }
29 throw 'Casting to number results in NaN';
30 }
31
32 static optionalNumber(data: any): number|undefined {
33 return data !== undefined ? HARBase.safeNumber(data) : undefined;
34 }
35
36 static optionalString(data: any): string|undefined {
37 return data !== undefined ? String(data) : undefined;
38 }
39
40 customAsString(name: string): string|undefined {
41 const value = this.custom.get(name);
42 if (!value) {
43 return undefined;
44 }
45 return String(value);
46 }
47
48 customAsNumber(name: string): number|undefined {
49 const value = this.custom.get(name);
50 if (!value) {
51 return undefined;
52 }
53 const numberValue = Number(value);
54 if (Number.isNaN(numberValue)) {
55 return undefined;
56 }
57 return numberValue;
58 }
59
60 customAsArray(name: string): any[]|undefined {
61 const value = this.custom.get(name);
62 if (!value) {
63 return undefined;
64 }
65 return Array.isArray(value) ? value : undefined;
66 }
67
68 customInitiator(): HARInitiator|undefined {
69 return this.custom.get('initiator');
70 }
71}
72
73export class HARRoot extends HARBase {
74 log: HARLog;
75 constructor(data: any) {
76 super(data);
77 this.log = new HARLog(data['log']);
78 }
79}
80
81export class HARLog extends HARBase {
82 version: string;
83 creator: HARCreator;
84 browser: HARCreator|undefined;
85 pages: HARPage[];
86 entries: HAREntry[];
87 comment: string|undefined;
88 constructor(data: any) {
89 super(data);
90 this.version = String(data['version']);
91 this.creator = new HARCreator(data['creator']);
92 this.browser = data['browser'] ? new HARCreator(data['browser']) : undefined;
93 this.pages = Array.isArray(data['pages']) ? data['pages'].map(page => new HARPage(page)) : [];
94 if (!Array.isArray(data['entries'])) {
95 throw 'log.entries is expected to be an array';
96 }
97 this.entries = data['entries'].map(entry => new HAREntry(entry));
98 this.comment = HARBase.optionalString(data['comment']);
99 }
100}
101
102class HARCreator extends HARBase {
103 name: string;
104 version: string;
105 comment: string|undefined;
106 constructor(data: any) {
107 super(data);
108 this.name = String(data['name']);
109 this.version = String(data['version']);
110 this.comment = HARBase.optionalString(data['comment']);
111 }
112}
113
114export class HARPage extends HARBase {
115 startedDateTime: Date;
116 id: string;
117 title: string;
118 pageTimings: HARPageTimings;
119 comment: string|undefined;
120 constructor(data: any) {
121 super(data);
122 this.startedDateTime = HARBase.safeDate(data['startedDateTime']);
123 this.id = String(data['id']);
124 this.title = String(data['title']);
125 this.pageTimings = new HARPageTimings(data['pageTimings']);
126 this.comment = HARBase.optionalString(data['comment']);
127 }
128}
129
130class HARPageTimings extends HARBase {
131 onContentLoad: number|undefined;
132 onLoad: number|undefined;
133 comment: string|undefined;
134 constructor(data: any) {
135 super(data);
136 this.onContentLoad = HARBase.optionalNumber(data['onContentLoad']);
137 this.onLoad = HARBase.optionalNumber(data['onLoad']);
138 this.comment = HARBase.optionalString(data['comment']);
139 }
140}
141
142export class HAREntry extends HARBase {
143 pageref: string|undefined;
144 startedDateTime: Date;
145 time: number;
146 request: HARRequest;
147 response: HARResponse;
148 cache: {};
149 timings: HARTimings;
150 serverIPAddress: string|undefined;
151 connection: string|undefined;
152 comment: string|undefined;
153 constructor(data: any) {
154 super(data);
155 this.pageref = HARBase.optionalString(data['pageref']);
156 this.startedDateTime = HARBase.safeDate(data['startedDateTime']);
157 this.time = HARBase.safeNumber(data['time']);
158 this.request = new HARRequest(data['request']);
159 this.response = new HARResponse(data['response']);
160 this.cache = {}; // Not yet implemented.
161 this.timings = new HARTimings(data['timings']);
162 this.serverIPAddress = HARBase.optionalString(data['serverIPAddress']);
163 this.connection = HARBase.optionalString(data['connection']);
164 this.comment = HARBase.optionalString(data['comment']);
165
166 // Chrome specific.
167 this.custom.set('fromCache', HARBase.optionalString(data['_fromCache']));
168 this.custom.set('initiator', this.importInitiator(data['_initiator']));
169 this.custom.set('priority', HARBase.optionalString(data['_priority']));
170 this.custom.set('resourceType', HARBase.optionalString(data['_resourceType']));
171 this.custom.set('webSocketMessages', this.importWebSocketMessages(data['_webSocketMessages']));
172 }
173
174 private importInitiator(initiator: any): HARInitiator|undefined {
175 if (typeof initiator !== 'object') {
176 return;
177 }
178
179 return new HARInitiator(initiator);
180 }
181
182 private importWebSocketMessages(inputMessages: any): HARWebSocketMessage[]|undefined {
183 if (!Array.isArray(inputMessages)) {
184 return;
185 }
186
187 const outputMessages = [];
188 for (const message of inputMessages) {
189 if (typeof message !== 'object') {
190 return;
191 }
192 outputMessages.push(new HARWebSocketMessage(message));
193 }
194 return outputMessages;
195 }
196}
197
198class HARRequest extends HARBase {
199 method: string;
200 url: string;
201 httpVersion: string;
202 cookies: HARCookie[];
203 headers: HARHeader[];
204 queryString: HARQueryString[];
205 postData: HARPostData|undefined;
206 headersSize: number;
207 bodySize: number;
208 comment: string|undefined;
209 constructor(data: any) {
210 super(data);
211 this.method = String(data['method']);
212 this.url = String(data['url']);
213 this.httpVersion = String(data['httpVersion']);
214 this.cookies = Array.isArray(data['cookies']) ? data['cookies'].map(cookie => new HARCookie(cookie)) : [];
215 this.headers = Array.isArray(data['headers']) ? data['headers'].map(header => new HARHeader(header)) : [];
216 this.queryString = Array.isArray(data['queryString']) ? data['queryString'].map(qs => new HARQueryString(qs)) : [];
217 this.postData = data['postData'] ? new HARPostData(data['postData']) : undefined;
218 this.headersSize = HARBase.safeNumber(data['headersSize']);
219 this.bodySize = HARBase.safeNumber(data['bodySize']);
220 this.comment = HARBase.optionalString(data['comment']);
221 }
222}
223
224class HARResponse extends HARBase {
225 status: number;
226 statusText: string;
227 httpVersion: string;
228 cookies: HARCookie[];
229 headers: HARHeader[];
230 content: HARContent;
231 redirectURL: string;
232 headersSize: number;
233 bodySize: number;
234 comment: string|undefined;
235 constructor(data: any) {
236 super(data);
237 this.status = HARBase.safeNumber(data['status']);
238 this.statusText = String(data['statusText']);
239 this.httpVersion = String(data['httpVersion']);
240 this.cookies = Array.isArray(data['cookies']) ? data['cookies'].map(cookie => new HARCookie(cookie)) : [];
241 this.headers = Array.isArray(data['headers']) ? data['headers'].map(header => new HARHeader(header)) : [];
242 this.content = new HARContent(data['content']);
243 this.redirectURL = String(data['redirectURL']);
244 this.headersSize = HARBase.safeNumber(data['headersSize']);
245 this.bodySize = HARBase.safeNumber(data['bodySize']);
246 this.comment = HARBase.optionalString(data['comment']);
247
248 // Chrome specific.
249 this.custom.set('transferSize', HARBase.optionalNumber(data['_transferSize']));
250 this.custom.set('error', HARBase.optionalString(data['_error']));
251 }
252}
253
254class HARCookie extends HARBase {
255 name: string;
256 value: string;
257 path: string|undefined;
258 domain: string|undefined;
259 expires: Date|undefined;
260 httpOnly: boolean|undefined;
261 secure: boolean|undefined;
262 comment: string|undefined;
263 constructor(data: any) {
264 super(data);
265 this.name = String(data['name']);
266 this.value = String(data['value']);
267 this.path = HARBase.optionalString(data['path']);
268 this.domain = HARBase.optionalString(data['domain']);
269 this.expires = data['expires'] ? HARBase.safeDate(data['expires']) : undefined;
270 this.httpOnly = data['httpOnly'] !== undefined ? Boolean(data['httpOnly']) : undefined;
271 this.secure = data['secure'] !== undefined ? Boolean(data['secure']) : undefined;
272 this.comment = HARBase.optionalString(data['comment']);
273 }
274}
275
276class HARHeader extends HARBase {
277 name: string;
278 value: string;
279 comment: string|undefined;
280 constructor(data: any) {
281 super(data);
282 this.name = String(data['name']);
283 this.value = String(data['value']);
284 this.comment = HARBase.optionalString(data['comment']);
285 }
286}
287
288class HARQueryString extends HARBase {
289 name: string;
290 value: string;
291 comment: string|undefined;
292 constructor(data: any) {
293 super(data);
294 this.name = String(data['name']);
295 this.value = String(data['value']);
296 this.comment = HARBase.optionalString(data['comment']);
297 }
298}
299
300class HARPostData extends HARBase {
301 mimeType: string;
302 params: HARParam[];
303 text: string;
304 comment: string|undefined;
305 constructor(data: any) {
306 super(data);
307 this.mimeType = String(data['mimeType']);
308 this.params = Array.isArray(data['params']) ? data['params'].map(param => new HARParam(param)) : [];
309 this.text = String(data['text']);
310 this.comment = HARBase.optionalString(data['comment']);
311 }
312}
313
314export class HARParam extends HARBase {
315 name: string;
316 value: string|undefined;
317 fileName: string|undefined;
318 contentType: string|undefined;
319 comment: string|undefined;
320 constructor(data: any) {
321 super(data);
322 this.name = String(data['name']);
323 this.value = HARBase.optionalString(data['value']);
324 this.fileName = HARBase.optionalString(data['fileName']);
325 this.contentType = HARBase.optionalString(data['contentType']);
326 this.comment = HARBase.optionalString(data['comment']);
327 }
328}
329
330class HARContent extends HARBase {
331 size: number;
332 compression: number|undefined;
333 mimeType: string;
334 text: string|undefined;
335 encoding: string|undefined;
336 comment: string|undefined;
337 constructor(data: any) {
338 super(data);
339 this.size = HARBase.safeNumber(data['size']);
340 this.compression = HARBase.optionalNumber(data['compression']);
341 this.mimeType = String(data['mimeType']);
342 this.text = HARBase.optionalString(data['text']);
343 this.encoding = HARBase.optionalString(data['encoding']);
344 this.comment = HARBase.optionalString(data['comment']);
345 }
346}
347
348export class HARTimings extends HARBase {
349 blocked: number|undefined;
350 dns: number|undefined;
351 connect: number|undefined;
352 send: number;
353 wait: number;
354 receive: number;
355 ssl: number|undefined;
356 comment: string|undefined;
357 constructor(data: any) {
358 super(data);
359 this.blocked = HARBase.optionalNumber(data['blocked']);
360 this.dns = HARBase.optionalNumber(data['dns']);
361 this.connect = HARBase.optionalNumber(data['connect']);
362 this.send = HARBase.safeNumber(data['send']);
363 this.wait = HARBase.safeNumber(data['wait']);
364 this.receive = HARBase.safeNumber(data['receive']);
365 this.ssl = HARBase.optionalNumber(data['ssl']);
366 this.comment = HARBase.optionalString(data['comment']);
367
368 // Chrome specific.
369 this.custom.set('blocked_queueing', HARBase.optionalNumber(data['_blocked_queueing']));
370 this.custom.set('blocked_proxy', HARBase.optionalNumber(data['_blocked_proxy']));
371 }
372}
373
374export class HARInitiator extends HARBase {
375 type: string|undefined;
376 url: string|undefined;
377 lineNumber: number|undefined;
378 /**
379 * Based on Initiator defined in browser_protocol.pdl
380 */
381 constructor(data: any) {
382 super(data);
383 this.type = HARBase.optionalString(data['type']);
384 this.url = HARBase.optionalString(data['url']);
385 this.lineNumber = HARBase.optionalNumber(data['lineNumber']);
386 }
387}
388
389class HARWebSocketMessage extends HARBase {
390 time: number|undefined;
391 opcode: number|undefined;
392 data: string|undefined;
393 type: string|undefined;
394 constructor(data: any) {
395 super(data);
396 this.time = HARBase.optionalNumber(data['time']);
397 this.opcode = HARBase.optionalNumber(data['opcode']);
398 this.data = HARBase.optionalString(data['data']);
399 this.type = HARBase.optionalString(data['type']);
400 }
401}