1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Joseph Pecoraro 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 WebInspector.CookieItemsView = function(treeElement, cookieDomain) 31 { 32 WebInspector.View.call(this); 33 34 this.element.addStyleClass("storage-view"); 35 36 this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); 37 this._deleteButton.visible = false; 38 this._deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false); 39 40 this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); 41 this._refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); 42 43 this._treeElement = treeElement; 44 this._cookieDomain = cookieDomain; 45 46 this._emptyMsgElement = document.createElement("div"); 47 this._emptyMsgElement.className = "storage-empty-view"; 48 this._emptyMsgElement.textContent = WebInspector.UIString("This site has no cookies."); 49 this.element.appendChild(this._emptyMsgElement); 50 } 51 52 WebInspector.CookieItemsView.prototype = { 53 get statusBarItems() 54 { 55 return [this._refreshButton.element, this._deleteButton.element]; 56 }, 57 58 show: function(parentElement) 59 { 60 WebInspector.View.prototype.show.call(this, parentElement); 61 this._update(); 62 }, 63 64 hide: function() 65 { 66 WebInspector.View.prototype.hide.call(this); 67 this._deleteButton.visible = false; 68 }, 69 70 resize: function() 71 { 72 if (this._cookiesTable) 73 this._cookiesTable.updateWidths(); 74 }, 75 76 _update: function() 77 { 78 WebInspector.Cookies.getCookiesAsync(this._updateWithCookies.bind(this)); 79 }, 80 81 _updateWithCookies: function(allCookies, isAdvanced) 82 { 83 this._cookies = isAdvanced ? this._filterCookiesForDomain(allCookies) : allCookies; 84 85 if (!this._cookies.length) { 86 // Nothing to show. 87 this._emptyMsgElement.removeStyleClass("hidden"); 88 this._deleteButton.visible = false; 89 if (this._cookiesTable) 90 this._cookiesTable.element.addStyleClass("hidden"); 91 return; 92 } 93 94 if (!this._cookiesTable) { 95 this._cookiesTable = isAdvanced ? new WebInspector.CookiesTable(this._cookieDomain, false, this._deleteCookie.bind(this)) : new WebInspector.SimpleCookiesTable(); 96 this.element.appendChild(this._cookiesTable.element); 97 } 98 99 this._cookiesTable.setCookies(this._cookies); 100 this._cookiesTable.element.removeStyleClass("hidden"); 101 this._emptyMsgElement.addStyleClass("hidden"); 102 if (isAdvanced) { 103 this._treeElement.subtitle = String.sprintf(WebInspector.UIString("%d cookies (%s)"), this._cookies.length, 104 Number.bytesToString(this._totalSize)); 105 this._deleteButton.visible = true; 106 } 107 this._cookiesTable.updateWidths(); 108 }, 109 110 _filterCookiesForDomain: function(allCookies) 111 { 112 var cookies = []; 113 var resourceURLsForDocumentURL = []; 114 this._totalSize = 0; 115 116 function populateResourcesForDocuments(resource) 117 { 118 var url = resource.documentURL.asParsedURL(); 119 if (url && url.host == this._cookieDomain) 120 resourceURLsForDocumentURL.push(resource.url); 121 } 122 WebInspector.forAllResources(populateResourcesForDocuments.bind(this)); 123 124 for (var i = 0; i < allCookies.length; ++i) { 125 var pushed = false; 126 var size = allCookies[i].size; 127 for (var j = 0; j < resourceURLsForDocumentURL.length; ++j) { 128 var resourceURL = resourceURLsForDocumentURL[j]; 129 if (WebInspector.Cookies.cookieMatchesResourceURL(allCookies[i], resourceURL)) { 130 this._totalSize += size; 131 if (!pushed) { 132 pushed = true; 133 cookies.push(allCookies[i]); 134 } 135 } 136 } 137 } 138 return cookies; 139 }, 140 141 _deleteCookie: function(cookie) 142 { 143 PageAgent.deleteCookie(cookie.name, this._cookieDomain); 144 this._update(); 145 }, 146 147 _deleteButtonClicked: function() 148 { 149 if (this._cookiesTable.selectedCookie) 150 this._deleteCookie(this._cookiesTable.selectedCookie); 151 }, 152 153 _refreshButtonClicked: function(event) 154 { 155 this._update(); 156 } 157 } 158 159 WebInspector.CookieItemsView.prototype.__proto__ = WebInspector.View.prototype; 160 161 WebInspector.SimpleCookiesTable = function() 162 { 163 this.element = document.createElement("div"); 164 var columns = {}; 165 columns[0] = {}; 166 columns[1] = {}; 167 columns[0].title = WebInspector.UIString("Name"); 168 columns[1].title = WebInspector.UIString("Value"); 169 170 this._dataGrid = new WebInspector.DataGrid(columns); 171 this._dataGrid.autoSizeColumns(20, 80); 172 this.element.appendChild(this._dataGrid.element); 173 this._dataGrid.updateWidths(); 174 } 175 176 WebInspector.SimpleCookiesTable.prototype = { 177 setCookies: function(cookies) 178 { 179 this._dataGrid.removeChildren(); 180 var addedCookies = {}; 181 for (var i = 0; i < cookies.length; ++i) { 182 if (addedCookies[cookies[i].name]) 183 continue; 184 addedCookies[cookies[i].name] = true; 185 var data = {}; 186 data[0] = cookies[i].name; 187 data[1] = cookies[i].value; 188 189 var node = new WebInspector.DataGridNode(data, false); 190 node.selectable = true; 191 this._dataGrid.appendChild(node); 192 } 193 this._dataGrid.children[0].selected = true; 194 }, 195 196 resize: function() 197 { 198 if (this._dataGrid) 199 this._dataGrid.updateWidths(); 200 } 201 } 202 203 204 WebInspector.Cookies = {} 205 206 WebInspector.Cookies.getCookiesAsync = function(callback) 207 { 208 function mycallback(error, cookies, cookiesString) 209 { 210 if (error) 211 return; 212 if (cookiesString) 213 callback(WebInspector.Cookies.buildCookiesFromString(cookiesString), false); 214 else 215 callback(cookies, true); 216 } 217 218 PageAgent.getCookies(mycallback); 219 } 220 221 WebInspector.Cookies.buildCookiesFromString = function(rawCookieString) 222 { 223 var rawCookies = rawCookieString.split(/;\s*/); 224 var cookies = []; 225 226 if (!(/^\s*$/.test(rawCookieString))) { 227 for (var i = 0; i < rawCookies.length; ++i) { 228 var cookie = rawCookies[i]; 229 var delimIndex = cookie.indexOf("="); 230 var name = cookie.substring(0, delimIndex); 231 var value = cookie.substring(delimIndex + 1); 232 var size = name.length + value.length; 233 cookies.push({ name: name, value: value, size: size }); 234 } 235 } 236 237 return cookies; 238 } 239 240 WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL) 241 { 242 var url = resourceURL.asParsedURL(); 243 if (!url || !this.cookieDomainMatchesResourceDomain(cookie.domain, url.host)) 244 return false; 245 return (url.path.indexOf(cookie.path) === 0 246 && (!cookie.port || url.port == cookie.port) 247 && (!cookie.secure || url.scheme === "https")); 248 } 249 250 WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain) 251 { 252 if (cookieDomain.charAt(0) !== '.') 253 return resourceDomain === cookieDomain; 254 return !!resourceDomain.match(new RegExp("^([^\\.]+\\.)?" + cookieDomain.substring(1).escapeForRegExp() + "$"), "i"); 255 } 256