Home | History | Annotate | Download | only in front-end
      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 
     29 WebInspector.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 
     40 WebInspector.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
     98 WebInspector.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 
    135 WebInspector.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 
    569 WebInspector.Resource.prototype.__proto__ = WebInspector.Object.prototype;
    570 
    571 WebInspector.Resource.CompareByStartTime = function(a, b)
    572 {
    573     return a.startTime - b.startTime;
    574 }
    575 
    576 WebInspector.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 
    585 WebInspector.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 
    594 WebInspector.Resource.CompareByDuration = function(a, b)
    595 {
    596     return a.duration - b.duration;
    597 }
    598 
    599 WebInspector.Resource.CompareByLatency = function(a, b)
    600 {
    601     return a.latency - b.latency;
    602 }
    603 
    604 WebInspector.Resource.CompareBySize = function(a, b)
    605 {
    606     return a.contentLength - b.contentLength;
    607 }
    608 
    609 WebInspector.Resource.StatusTextForCode = function(code)
    610 {
    611     return code ? code + " " + WebInspector.Resource.StatusText[code] : "";
    612 }
    613