• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29WebInspector.Resource = function(identifier, url)
30{
31    this.identifier = identifier;
32    this._url = url;
33    this._startTime = -1;
34    this._endTime = -1;
35    this._requestMethod = "";
36    this._requestFormData = "";
37    this._category = WebInspector.resourceCategories.other;
38}
39
40WebInspector.Resource.StatusText = {
41    100: "Continue",
42    101: "Switching Protocols",
43    102: "Processing (WebDav)",
44    200: "OK",
45    201: "Created",
46    202: "Accepted",
47    203: "Non-Authoritative Information",
48    204: "No Content",
49    205: "Reset Content",
50    206: "Partial Content",
51    207: "Multi-Status (WebDav)",
52    300: "Multiple Choices",
53    301: "Moved Permanently",
54    302: "Found",
55    303: "See Other",
56    304: "Not Modified",
57    305: "Use Proxy",
58    306: "Switch Proxy",
59    307: "Temporary",
60    400: "Bad Request",
61    401: "Unauthorized",
62    402: "Payment Required",
63    403: "Forbidden",
64    404: "Not Found",
65    405: "Method Not Allowed",
66    406: "Not Acceptable",
67    407: "Proxy Authentication Required",
68    408: "Request Timeout",
69    409: "Conflict",
70    410: "Gone",
71    411: "Length Required",
72    412: "Precondition Failed",
73    413: "Request Entity Too Large",
74    414: "Request-URI Too Long",
75    415: "Unsupported Media Type",
76    416: "Requested Range Not Satisfiable",
77    417: "Expectation Failed",
78    418: "I'm a teapot",
79    422: "Unprocessable Entity (WebDav)",
80    423: "Locked (WebDav)",
81    424: "Failed Dependency (WebDav)",
82    425: "Unordered Collection",
83    426: "Upgrade Required",
84    449: "Retry With",
85    500: "Internal Server Error",
86    501: "Not Implemented",
87    502: "Bad Gateway",
88    503: "Service Unavailable",
89    504: "Gateway Timeout",
90    505: "HTTP Version Not Supported",
91    506: "Variant Also Negotiates",
92    507: "Insufficient Storage (WebDav)",
93    509: "Bandwidth Limit Exceeded",
94    510: "Not Extended"
95};
96
97// Keep these in sync with WebCore::InspectorResource::Type
98WebInspector.Resource.Type = {
99    Document:   0,
100    Stylesheet: 1,
101    Image:      2,
102    Font:       3,
103    Script:     4,
104    XHR:        5,
105    Media:      6,
106    Other:      7,
107
108    isTextType: function(type)
109    {
110        return (type === this.Document) || (type === this.Stylesheet) || (type === this.Script) || (type === this.XHR);
111    },
112
113    toString: function(type)
114    {
115        switch (type) {
116            case this.Document:
117                return WebInspector.UIString("document");
118            case this.Stylesheet:
119                return WebInspector.UIString("stylesheet");
120            case this.Image:
121                return WebInspector.UIString("image");
122            case this.Font:
123                return WebInspector.UIString("font");
124            case this.Script:
125                return WebInspector.UIString("script");
126            case this.XHR:
127                return WebInspector.UIString("XHR");
128            case this.Other:
129            default:
130                return WebInspector.UIString("other");
131        }
132    }
133}
134
135WebInspector.Resource.prototype = {
136    get url()
137    {
138        return this._url;
139    },
140
141    set url(x)
142    {
143        if (this._url === x)
144            return;
145
146        var oldURL = this._url;
147        this._url = x;
148
149        // FIXME: We should make the WebInspector object listen for the "url changed" event.
150        // Then resourceURLChanged can be removed.
151        WebInspector.resourceURLChanged(this, oldURL);
152
153        this.dispatchEventToListeners("url changed");
154    },
155
156    get documentURL()
157    {
158        return this._documentURL;
159    },
160
161    set documentURL(x)
162    {
163        if (this._documentURL === x)
164            return;
165        this._documentURL = x;
166    },
167
168    get domain()
169    {
170        return this._domain;
171    },
172
173    set domain(x)
174    {
175        if (this._domain === x)
176            return;
177        this._domain = x;
178    },
179
180    get lastPathComponent()
181    {
182        return this._lastPathComponent;
183    },
184
185    set lastPathComponent(x)
186    {
187        if (this._lastPathComponent === x)
188            return;
189        this._lastPathComponent = x;
190        this._lastPathComponentLowerCase = x ? x.toLowerCase() : null;
191    },
192
193    get displayName()
194    {
195        var title = this.lastPathComponent;
196        if (!title)
197            title = this.displayDomain;
198        if (!title && this.url)
199            title = this.url.trimURL(WebInspector.mainResource ? WebInspector.mainResource.domain : "");
200        if (title === "/")
201            title = this.url;
202        return title;
203    },
204
205    get displayDomain()
206    {
207        // WebInspector.Database calls this, so don't access more than this.domain.
208        if (this.domain && (!WebInspector.mainResource || (WebInspector.mainResource && this.domain !== WebInspector.mainResource.domain)))
209            return this.domain;
210        return "";
211    },
212
213    get startTime()
214    {
215        return this._startTime || -1;
216    },
217
218    set startTime(x)
219    {
220        if (this._startTime === x)
221            return;
222
223        this._startTime = x;
224
225        if (WebInspector.panels.resources)
226            WebInspector.panels.resources.refreshResource(this);
227    },
228
229    get responseReceivedTime()
230    {
231        return this._responseReceivedTime || -1;
232    },
233
234    set responseReceivedTime(x)
235    {
236        if (this._responseReceivedTime === x)
237            return;
238
239        this._responseReceivedTime = x;
240
241        if (WebInspector.panels.resources)
242            WebInspector.panels.resources.refreshResource(this);
243    },
244
245    get endTime()
246    {
247        return this._endTime || -1;
248    },
249
250    set endTime(x)
251    {
252        if (this._endTime === x)
253            return;
254
255        this._endTime = x;
256
257        if (WebInspector.panels.resources)
258            WebInspector.panels.resources.refreshResource(this);
259    },
260
261    get duration()
262    {
263        if (this._endTime === -1 || this._startTime === -1)
264            return -1;
265        return this._endTime - this._startTime;
266    },
267
268    get latency()
269    {
270        if (this._responseReceivedTime === -1 || this._startTime === -1)
271            return -1;
272        return this._responseReceivedTime - this._startTime;
273    },
274
275    get contentLength()
276    {
277        return this._contentLength || 0;
278    },
279
280    set contentLength(x)
281    {
282        if (this._contentLength === x)
283            return;
284
285        this._contentLength = x;
286
287        if (WebInspector.panels.resources)
288            WebInspector.panels.resources.refreshResource(this);
289    },
290
291    get expectedContentLength()
292    {
293        return this._expectedContentLength || 0;
294    },
295
296    set expectedContentLength(x)
297    {
298        if (this._expectedContentLength === x)
299            return;
300        this._expectedContentLength = x;
301    },
302
303    get finished()
304    {
305        return this._finished;
306    },
307
308    set finished(x)
309    {
310        if (this._finished === x)
311            return;
312
313        this._finished = x;
314
315        if (x) {
316            this._checkWarnings();
317            this.dispatchEventToListeners("finished");
318        }
319    },
320
321    get failed()
322    {
323        return this._failed;
324    },
325
326    set failed(x)
327    {
328        this._failed = x;
329    },
330
331    get category()
332    {
333        return this._category;
334    },
335
336    set category(x)
337    {
338        if (this._category === x)
339            return;
340
341        var oldCategory = this._category;
342        if (oldCategory)
343            oldCategory.removeResource(this);
344
345        this._category = x;
346
347        if (this._category)
348            this._category.addResource(this);
349
350        if (WebInspector.panels.resources) {
351            WebInspector.panels.resources.refreshResource(this);
352            WebInspector.panels.resources.recreateViewForResourceIfNeeded(this);
353        }
354    },
355
356    get mimeType()
357    {
358        return this._mimeType;
359    },
360
361    set mimeType(x)
362    {
363        if (this._mimeType === x)
364            return;
365
366        this._mimeType = x;
367    },
368
369    get type()
370    {
371        return this._type;
372    },
373
374    set type(x)
375    {
376        if (this._type === x)
377            return;
378
379        this._type = x;
380
381        switch (x) {
382            case WebInspector.Resource.Type.Document:
383                this.category = WebInspector.resourceCategories.documents;
384                break;
385            case WebInspector.Resource.Type.Stylesheet:
386                this.category = WebInspector.resourceCategories.stylesheets;
387                break;
388            case WebInspector.Resource.Type.Script:
389                this.category = WebInspector.resourceCategories.scripts;
390                break;
391            case WebInspector.Resource.Type.Image:
392                this.category = WebInspector.resourceCategories.images;
393                break;
394            case WebInspector.Resource.Type.Font:
395                this.category = WebInspector.resourceCategories.fonts;
396                break;
397            case WebInspector.Resource.Type.XHR:
398                this.category = WebInspector.resourceCategories.xhr;
399                break;
400            case WebInspector.Resource.Type.Other:
401            default:
402                this.category = WebInspector.resourceCategories.other;
403                break;
404        }
405    },
406
407    get requestHeaders()
408    {
409        if (this._requestHeaders === undefined)
410            this._requestHeaders = {};
411        return this._requestHeaders;
412    },
413
414    set requestHeaders(x)
415    {
416        if (this._requestHeaders === x)
417            return;
418
419        this._requestHeaders = x;
420        delete this._sortedRequestHeaders;
421
422        this.dispatchEventToListeners("requestHeaders changed");
423    },
424
425    get sortedRequestHeaders()
426    {
427        if (this._sortedRequestHeaders !== undefined)
428            return this._sortedRequestHeaders;
429
430        this._sortedRequestHeaders = [];
431        for (var key in this.requestHeaders)
432            this._sortedRequestHeaders.push({header: key, value: this.requestHeaders[key]});
433        this._sortedRequestHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
434
435        return this._sortedRequestHeaders;
436    },
437
438    get responseHeaders()
439    {
440        if (this._responseHeaders === undefined)
441            this._responseHeaders = {};
442        return this._responseHeaders;
443    },
444
445    set responseHeaders(x)
446    {
447        if (this._responseHeaders === x)
448            return;
449
450        this._responseHeaders = x;
451        delete this._sortedResponseHeaders;
452
453        this.dispatchEventToListeners("responseHeaders changed");
454    },
455
456    get sortedResponseHeaders()
457    {
458        if (this._sortedResponseHeaders !== undefined)
459            return this._sortedResponseHeaders;
460
461        this._sortedResponseHeaders = [];
462        for (var key in this.responseHeaders)
463            this._sortedResponseHeaders.push({header: key, value: this.responseHeaders[key]});
464        this._sortedResponseHeaders.sort(function(a,b) { return a.header.localeCompare(b.header) });
465
466        return this._sortedResponseHeaders;
467    },
468
469    get scripts()
470    {
471        if (!("_scripts" in this))
472            this._scripts = [];
473        return this._scripts;
474    },
475
476    addScript: function(script)
477    {
478        if (!script)
479            return;
480        this.scripts.unshift(script);
481        script.resource = this;
482    },
483
484    removeAllScripts: function()
485    {
486        if (!this._scripts)
487            return;
488
489        for (var i = 0; i < this._scripts.length; ++i) {
490            if (this._scripts[i].resource === this)
491                delete this._scripts[i].resource;
492        }
493
494        delete this._scripts;
495    },
496
497    removeScript: function(script)
498    {
499        if (!script)
500            return;
501
502        if (script.resource === this)
503            delete script.resource;
504
505        if (!this._scripts)
506            return;
507
508        this._scripts.remove(script);
509    },
510
511    get errors()
512    {
513        return this._errors || 0;
514    },
515
516    set errors(x)
517    {
518        this._errors = x;
519    },
520
521    get warnings()
522    {
523        return this._warnings || 0;
524    },
525
526    set warnings(x)
527    {
528        this._warnings = x;
529    },
530
531    _mimeTypeIsConsistentWithType: function()
532    {
533        if (typeof this.type === "undefined"
534         || this.type === WebInspector.Resource.Type.Other
535         || this.type === WebInspector.Resource.Type.XHR)
536            return true;
537
538        if (this.mimeType in WebInspector.MIMETypes)
539            return this.type in WebInspector.MIMETypes[this.mimeType];
540
541        return false;
542    },
543
544    _checkWarnings: function()
545    {
546        for (var warning in WebInspector.Warnings)
547            this._checkWarning(WebInspector.Warnings[warning]);
548    },
549
550    _checkWarning: function(warning)
551    {
552        var msg;
553        switch (warning.id) {
554            case WebInspector.Warnings.IncorrectMIMEType.id:
555                if (!this._mimeTypeIsConsistentWithType())
556                    msg = new WebInspector.ConsoleMessage(WebInspector.ConsoleMessage.MessageSource.Other,
557                        WebInspector.ConsoleMessage.MessageType.Log,
558                        WebInspector.ConsoleMessage.MessageLevel.Warning, -1, this.url, null, 1,
559                        String.sprintf(WebInspector.Warnings.IncorrectMIMEType.message,
560                        WebInspector.Resource.Type.toString(this.type), this.mimeType));
561                break;
562        }
563
564        if (msg)
565            WebInspector.console.addMessage(msg);
566    }
567}
568
569WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
570
571WebInspector.Resource.CompareByStartTime = function(a, b)
572{
573    return a.startTime - b.startTime;
574}
575
576WebInspector.Resource.CompareByResponseReceivedTime = function(a, b)
577{
578    var aVal = a.responseReceivedTime;
579    var bVal = b.responseReceivedTime;
580    if (aVal === -1 ^ bVal === -1)
581        return bVal - aVal;
582    return aVal - bVal;
583}
584
585WebInspector.Resource.CompareByEndTime = function(a, b)
586{
587    var aVal = a.endTime;
588    var bVal = b.endTime;
589    if (aVal === -1 ^ bVal === -1)
590        return bVal - aVal;
591    return aVal - bVal;
592}
593
594WebInspector.Resource.CompareByDuration = function(a, b)
595{
596    return a.duration - b.duration;
597}
598
599WebInspector.Resource.CompareByLatency = function(a, b)
600{
601    return a.latency - b.latency;
602}
603
604WebInspector.Resource.CompareBySize = function(a, b)
605{
606    return a.contentLength - b.contentLength;
607}
608
609WebInspector.Resource.StatusTextForCode = function(code)
610{
611    return code ? code + " " + WebInspector.Resource.StatusText[code] : "";
612}
613