1 /* See license.txt for terms of usage */ 2 3 define([ 4 "firebug/lib/object", 5 "firebug/lib/xpcom", 6 "firebug/cookies/baseObserver", 7 "firebug/lib/http", 8 "firebug/chrome/tabWatcher", 9 "firebug/cookies/cookie", 10 "firebug/lib/options", 11 "firebug/cookies/cookieUtils", 12 "firebug/lib/array", 13 "firebug/chrome/firefox", 14 ], 15 function(Obj, Xpcom, BaseObserver, Http, TabWatcher, Cookie, Options, CookieUtils, Arr, Firefox) { 16 17 // ********************************************************************************************* // 18 // Constants 19 20 var Cc = Components.classes; 21 var Ci = Components.interfaces; 22 23 const cookieService = Xpcom.CCSV("@mozilla.org/cookieService;1", "nsICookieService"); 24 25 const panelName = "cookies"; 26 27 // ********************************************************************************************* // 28 // HTTP observer 29 30 /** 31 * @class Represents an observer for http-on-modify-request and 32 * http-on-examine-response events that are dispatched 33 * by Firefox when network request is executed and returned. 34 */ 35 var HttpObserver = Obj.extend(BaseObserver, 36 /** @lends HttpObserver */ 37 { 38 // nsIObserver 39 observe: function(aSubject, aTopic, aData) 40 { 41 try { 42 aSubject = aSubject.QueryInterface(Ci.nsIHttpChannel); 43 if (aTopic == "http-on-modify-request") { 44 this.onModifyRequest(aSubject); 45 } else if (aTopic == "http-on-examine-response") { 46 this.onExamineResponse(aSubject); 47 } 48 } 49 catch (err) 50 { 51 if (FBTrace.DBG_ERRORS) 52 FBTrace.sysout("cookies.HttpObserver.observe; EXCEPTION " + err, err); 53 } 54 }, 55 56 onModifyRequest: function(request) 57 { 58 var name = request.URI.spec; 59 var origName = request.originalURI.spec; 60 var win = Http.getWindowForRequest(request); 61 var tabId = Firebug.getTabIdForWindow(win); 62 63 // Firebus's natures is to display information for a tab. So, if there 64 // is no tab associated then end. 65 if (!tabId) 66 return; 67 68 // Dump debug information to the console. 69 if (FBTrace.DBG_COOKIES) 70 { 71 FBTrace.sysout("cookies.onModifyRequest: " + request.name); 72 FBTrace.sysout("cookies.Cookies sent: " + 73 cookieService.getCookieString(request.URI, request)); 74 } 75 76 // At this moment (specified by all the conditions) FB context doesn't exists yet. 77 // But the page already started loading and there are things to monitor. 78 // This is why the temporary context is created. It's used as a place where to 79 // store information (cookie events and hosts). All this info will be copied into 80 // the real FB context when it's created (see initContext). 81 if ((request.loadFlags & Ci.nsIHttpChannel.LOAD_DOCUMENT_URI) && 82 (request.loadGroup && request.loadGroup.groupObserver) && 83 (name == origName) && (win && win == win.parent)) 84 { 85 var browser = Firefox.getBrowserForWindow(win); 86 87 if (!Firebug.TabWatcher.shouldCreateContext(browser, name, null)) 88 { 89 if (FBTrace.DBG_COOKIES) 90 FBTrace.sysout("cookies.onModifyRequest; Activation logic says don't create " + 91 "temp context for: " + name); 92 return; 93 } 94 95 if (FBTrace.DBG_COOKIES && Firebug.CookieModule.contexts[tabId]) 96 FBTrace.sysout("cookies.!!! Temporary context exists for: " + tabId); 97 98 // Create temporary context 99 if (!Firebug.CookieModule.contexts[tabId]) 100 { 101 var tempContext = new TempContext(tabId); 102 Firebug.CookieModule.contexts[tabId] = tempContext; 103 104 if (FBTrace.DBG_COOKIES) 105 FBTrace.sysout("cookies.INIT temporary context for: " + tempContext.tabId); 106 107 tempContext.href = name; 108 Firebug.CookieModule.initTempContext(tempContext); 109 } 110 } 111 112 // Use the temporary context first, if it exists. There could be an old 113 // context (associated with this tab) for the previous URL. 114 var context = Firebug.CookieModule.contexts[tabId]; 115 context = context ? context : TabWatcher.getContextByWindow(win); 116 117 // The context doesn't have to exist due to the activation support. 118 if (!context) 119 { 120 if (FBTrace.DBG_COOKIES) 121 FBTrace.sysout("cookies.onModifyRequest: context is NOT available for:" + 122 request.URI.host + ", tabId: " + tabId); 123 return; 124 } 125 126 // Collect all the host (redirects, iframes) as cookies for all of them 127 // will be displayed. 128 var activeHosts = context.cookies.activeHosts; 129 var host = request.URI.host; 130 if (!activeHosts[host]) 131 { 132 activeHosts[host] = {host: host, path: request.URI.path}; 133 134 if (FBTrace.DBG_COOKIES) 135 FBTrace.sysout("cookies.New host (on-modify-request): " + 136 request.URI.host + ", tabId: " + tabId, activeHosts); 137 138 // Refresh the panel asynchronously. 139 if (context instanceof Firebug.TabContext) 140 context.invalidatePanels(panelName); 141 } 142 }, 143 144 onExamineResponse: function(request) 145 { 146 var win = Http.getWindowForRequest(request); 147 var tabId = Firebug.getTabIdForWindow(win); 148 if (!tabId) 149 return; 150 151 if (FBTrace.DBG_COOKIES) 152 FBTrace.sysout("cookies.onExamineResponse: " + request.name); 153 154 // Do not collect received cookies if they are not necessary. 155 if (!Options.get("cookies.logEvents") && !Options.get("cookies.showRejectedCookies")) 156 return; 157 158 // If logging to console is on, remember the set-cookie string, so 159 // these cookies can be displayed together e.g. with rejected message. 160 var setCookie; 161 request.visitResponseHeaders({ 162 visitHeader: function(header, value) { 163 if (header == "Set-Cookie") 164 setCookie = value; 165 } 166 }); 167 168 // Bail out if no cookies is received. 169 if (!setCookie) 170 return; 171 172 // Try to get the context from the contexts array first. The TabWatacher 173 // could return context for the previous page in this tab. 174 var context = Firebug.CookieModule.contexts[tabId]; 175 context = context ? context : TabWatcher.getContextByWindow(win); 176 177 // The context doesn't have to exist due to the activation support. 178 if (!context) 179 { 180 if (FBTrace.DBG_COOKIES) 181 FBTrace.sysout("cookies.onExamineResponse: context is NOT available for:" + 182 request.URI.host + ", tabId: " + tabId); 183 return; 184 } 185 186 // Associate the setCookie string with proper active host (active 187 // host can be the page itself or an embedded iframe or a XHR). 188 // Also remember originalURI so, the info where the cookies comes 189 // from can be displayed to the user. 190 var activeHosts = context.cookies.activeHosts; 191 var host = request.URI.host; 192 var activeHost = activeHosts[host]; 193 194 // Map of all received cookies. The key is cookie-host the value is 195 // an array with all cookies with the same host. 196 if (!context.cookies.activeCookies) 197 context.cookies.activeCookies = []; 198 199 if (!activeHost) 200 return; 201 202 var activeCookies = context.cookies.activeCookies; 203 204 // xxxHonza 205 // 1)the activeHost.receivedCookies array shouldn't be recreated 206 // if it's already there. 207 // 2) There can be more responses from the same domain (XHRs) and so, 208 // more received cookies within the page life. 209 // 3) The list should make sure that received cookies aren't duplicated. 210 // (the same cookie can be received multiple time). 211 // 4) Also, rejected cookies, are displayed in the cookie-list too and 212 // these shouldn't be duplicated. 213 // 5) This should be a map (key == the original host) 214 //if (!activeHost.receivedCookies) 215 activeHost.receivedCookies = []; 216 217 // Parse all received cookies and store them into activeHost info. 218 var cookies = setCookie.split("\n"); 219 for (var i=0; i<cookies.length; i++) 220 { 221 var cookie = CookieUtils.parseFromString(cookies[i]); 222 cookie.originalURI = request.originalURI; 223 if (!cookie.host) 224 cookie.host = host; 225 226 // Push into activeHosts 227 var cookieWrapper = new Cookie(CookieUtils.makeCookieObject(cookie)); 228 activeHost.receivedCookies.push(cookieWrapper); 229 230 // Push into activeCookies 231 if (!activeCookies[cookie.host]) 232 activeCookies[cookie.host] = []; 233 234 var activeCookiesForHost = activeCookies[cookie.host]; 235 activeCookiesForHost[CookieUtils.getCookieId(cookie)] = cookie; 236 237 if (FBTrace.DBG_COOKIES) 238 FBTrace.sysout("cookies.Cookie received: " + 239 cookie.host + ", cookie: " + cookie.name, cookie); 240 } 241 242 if (FBTrace.DBG_COOKIES) 243 FBTrace.sysout("cookies.Set-Cookie: " + setCookie, activeCookies); 244 } 245 }); 246 247 // ********************************************************************************************* // 248 // Temporary context 249 250 function TempContext(tabId) 251 { 252 this.tabId = tabId; 253 this.events = []; 254 } 255 256 TempContext.prototype.appendCookieEvent = function(subject, topic, data) 257 { 258 this.events.push({subject:subject, topic:topic, data:data}); 259 } 260 261 // ********************************************************************************************* // 262 263 return HttpObserver; 264 265 // ********************************************************************************************* // 266 }); 267 268