1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/xpcom",
  5     "firebug/lib/object",
  6     "firebug/lib/trace",
  7     "firebug/lib/http",
  8     "firebug/chrome/window",
  9     "firebug/net/netProgress",
 10     "firebug/net/netUtils"
 11 ],
 12 function(Xpcom, Obj, FBTrace, Http, Win, NetProgress, NetUtils) {
 13 
 14 // ********************************************************************************************* //
 15 // Constants
 16 
 17 var Cc = Components.classes;
 18 var Ci = Components.interfaces;
 19 var Cr = Components.results;
 20 
 21 var nsIHttpActivityObserver = Ci.nsIHttpActivityObserver;
 22 var nsISocketTransport = Ci.nsISocketTransport;
 23 
 24 var activeRequests = [];
 25 
 26 // ********************************************************************************************* //
 27 // Callbacks
 28 
 29 var startFile = NetProgress.prototype.startFile;
 30 var requestedHeaderFile = NetProgress.prototype.requestedHeaderFile;
 31 var respondedHeaderFile = NetProgress.prototype.respondedHeaderFile;
 32 var requestedFile = NetProgress.prototype.requestedFile;
 33 var respondedFile = NetProgress.prototype.respondedFile;
 34 var bodySentFile = NetProgress.prototype.bodySentFile;
 35 var responseStartedFile = NetProgress.prototype.responseStartedFile;
 36 var respondedCacheFile = NetProgress.prototype.respondedCacheFile;
 37 var connectingFile = NetProgress.prototype.connectingFile;
 38 var connectedFile = NetProgress.prototype.connectedFile;
 39 var waitingForFile = NetProgress.prototype.waitingForFile;
 40 var sendingFile = NetProgress.prototype.sendingFile;
 41 var receivingFile = NetProgress.prototype.receivingFile;
 42 var responseCompletedFile = NetProgress.prototype.responseCompletedFile;
 43 var closedFile = NetProgress.prototype.closedFile;
 44 var resolvingFile = NetProgress.prototype.resolvingFile;
 45 var resolvedFile = NetProgress.prototype.resolvedFile;
 46 var windowPaint = NetProgress.prototype.windowPaint;
 47 var timeStamp = NetProgress.prototype.timeStamp;
 48 var windowLoad = NetProgress.prototype.windowLoad;
 49 var contentLoad = NetProgress.prototype.contentLoad;
 50 
 51 // ********************************************************************************************* //
 52 // Activity Observer
 53 
 54 var NetHttpActivityObserver =
 55 {
 56     registered: false,
 57 
 58     registerObserver: function()
 59     {
 60         if (!Ci.nsIHttpActivityDistributor)
 61             return;
 62 
 63         if (this.registered)
 64             return;
 65 
 66         var distributor = this.getActivityDistributor();
 67         if (!distributor)
 68             return;
 69 
 70         distributor.addObserver(this);
 71         this.registered = true;
 72 
 73         if (FBTrace.DBG_ACTIVITYOBSERVER || FBTrace.DBG_OBSERVERS)
 74         {
 75             // import fbObserverService
 76             Components.utils.import("resource://firebug/observer-service.js");
 77             this.trackId = fbObserverService.track(Components.stack);
 78             FBTrace.sysout("activityObserver.registerObserver;"+this.trackId+" this.registered: "+this.registered);
 79         }
 80 
 81     },
 82 
 83     unregisterObserver: function()
 84     {
 85         if (!Ci.nsIHttpActivityDistributor)
 86             return;
 87 
 88         if (!this.registered)
 89             return;
 90 
 91         var distributor = this.getActivityDistributor();
 92         if (!distributor)
 93             return;
 94 
 95         distributor.removeObserver(this);
 96         this.registered = false;
 97 
 98         if (FBTrace.DBG_ACTIVITYOBSERVER || FBTrace.DBG_OBSERVERS)
 99         {
100             // import fbObserverService
101             Components.utils.import("resource://firebug/observer-service.js");
102             fbObserverService.untrack(this.trackId);
103             FBTrace.sysout("activityObserver.unregisterObserver;"+this.trackId+" this.registered: "+this.registered);
104         }
105 
106     },
107 
108     getActivityDistributor: function()
109     {
110         if (!this.activityDistributor)
111         {
112             try
113             {
114                 var hadClass = Cc["@mozilla.org/network/http-activity-distributor;1"];
115                 if (!hadClass)
116                     return null;
117 
118                 this.activityDistributor = hadClass.getService(Ci.nsIHttpActivityDistributor);
119 
120                 if (FBTrace.DBG_NET)
121                     FBTrace.sysout("net.NetHttpActivityObserver; Activity Observer Registered");
122             }
123             catch (err)
124             {
125                 if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS)
126                     FBTrace.sysout("net.NetHttpActivityObserver; Activity Observer EXCEPTION", err);
127             }
128         }
129         return this.activityDistributor;
130     },
131 
132     /* nsIActivityObserver */
133     observeActivity: function(httpChannel, activityType, activitySubtype, timestamp,
134         extraSizeData, extraStringData)
135     {
136         try
137         {
138             if (httpChannel instanceof Ci.nsIHttpChannel)
139                 this.observeRequest(httpChannel, activityType, activitySubtype, timestamp,
140                     extraSizeData, extraStringData);
141         }
142         catch (exc)
143         {
144             if ( (typeof(FBTrace) !== undefined) && FBTrace && FBTrace.DBG_ERRORS)  // then we are in some sane scope
145                 FBTrace.sysout("net.observeActivity: EXCEPTION "+exc, exc);
146         }
147     },
148 
149     observeRequest: function(httpChannel, activityType, activitySubtype, timestamp,
150         extraSizeData, extraStringData)
151     {
152         var win = Http.getWindowForRequest(httpChannel);
153         if (!win)
154         {
155             var index = activeRequests.indexOf(httpChannel);
156             if (index == -1)
157                 return;
158 
159             if (!(win = activeRequests[index+1]))
160                 return;
161         }
162 
163         var context = Firebug.connection.getContextByWindow(win);
164         var tabId = Win.getWindowProxyIdForWindow(win);
165         if (!(tabId && win))
166             return;
167 
168         var networkContext = Firebug.NetMonitor.contexts[tabId];
169         if (!networkContext)
170             networkContext = context ? context.netProgress : null;
171 
172         if (!networkContext)
173             return;
174 
175         var time = new Date();
176         time.setTime(timestamp/1000);
177 
178         if (FBTrace.DBG_ACTIVITYOBSERVER)
179         {
180             FBTrace.sysout("activityObserver.observeActivity; " +
181                 NetUtils.getTimeLabel(time) + ", " +
182                 Http.safeGetRequestName(httpChannel) + ", " +
183                 getActivityTypeDescription(activityType) + ", " +
184                 getActivitySubtypeDescription(activitySubtype) + ", " +
185                 extraSizeData,
186                 extraStringData);
187         }
188 
189         time = time.getTime();
190 
191         if (activityType == nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION)
192         {
193             if (activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_REQUEST_HEADER)
194             {
195                 activeRequests.push(httpChannel);
196                 activeRequests.push(win);
197 
198                 var isXHR = Http.isXHR(httpChannel);
199                 networkContext.post(requestedHeaderFile, [httpChannel, time, win, isXHR, extraStringData]);
200             }
201             else if (activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE)
202             {
203                 var index = activeRequests.indexOf(httpChannel);
204                 activeRequests.splice(index, 2);
205 
206                 networkContext.post(closedFile, [httpChannel, time]);
207             }
208             else if (activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_HEADER)
209                 networkContext.post(respondedHeaderFile, [httpChannel, time, extraStringData]);
210             else if (activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT)
211                 networkContext.post(bodySentFile, [httpChannel, time]);
212             else if (activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_START)
213                 networkContext.post(responseStartedFile, [httpChannel, time]);
214             else if (activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE)
215                 networkContext.post(responseCompletedFile, [httpChannel, time, extraSizeData]);
216         }
217         else if (activityType == nsIHttpActivityObserver.ACTIVITY_TYPE_SOCKET_TRANSPORT)
218         {
219             if (activitySubtype == nsISocketTransport.STATUS_RESOLVING)
220                 networkContext.post(resolvingFile, [httpChannel, time]);
221             //else if (activitySubtype == nsISocketTransport.STATUS_RESOLVED)
222             //    networkContext.post(resolvedFile, [httpChannel, time]);
223             else if (activitySubtype == nsISocketTransport.STATUS_CONNECTING_TO)
224                 networkContext.post(connectingFile, [httpChannel, time]);
225             else if (activitySubtype == nsISocketTransport.STATUS_CONNECTED_TO)
226                 networkContext.post(connectedFile, [httpChannel, time]);
227             else if (activitySubtype == nsISocketTransport.STATUS_SENDING_TO)
228                 networkContext.post(sendingFile, [httpChannel, time, extraSizeData]);
229             else if (activitySubtype == nsISocketTransport.STATUS_WAITING_FOR)
230                 networkContext.post(waitingForFile, [httpChannel, time]);
231             else if (activitySubtype == nsISocketTransport.STATUS_RECEIVING_FROM)
232                 networkContext.post(receivingFile, [httpChannel, time, extraSizeData]);
233         }
234     },
235 
236     /* nsISupports */
237     QueryInterface: function(iid)
238     {
239         if (iid.equals(Ci.nsISupports) ||
240             iid.equals(Ci.nsIActivityObserver)) {
241             return this;
242          }
243 
244         throw Cr.NS_ERROR_NO_INTERFACE;
245     }
246 }
247 
248 // ********************************************************************************************* //
249 // Activity Observer Tracing Support
250 
251 function getActivityTypeDescription(a)
252 {
253     switch (a)
254     {
255     case nsIHttpActivityObserver.ACTIVITY_TYPE_SOCKET_TRANSPORT:
256         return "ACTIVITY_TYPE_SOCKET_TRANSPORT";
257     case nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION:
258         return "ACTIVITY_TYPE_HTTP_TRANSACTION";
259     default:
260         return a;
261     }
262 }
263 
264 function getActivitySubtypeDescription(a)
265 {
266     switch (a)
267     {
268     case nsIHttpActivityObserver.ACTIVITY_SUBTYPE_REQUEST_HEADER:
269         return "ACTIVITY_SUBTYPE_REQUEST_HEADER";
270     case nsIHttpActivityObserver.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT:
271           return "ACTIVITY_SUBTYPE_REQUEST_BODY_SENT";
272     case nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_START:
273         return "ACTIVITY_SUBTYPE_RESPONSE_START";
274     case nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_HEADER:
275         return "ACTIVITY_SUBTYPE_RESPONSE_HEADER";
276     case nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE:
277         return "ACTIVITY_SUBTYPE_RESPONSE_COMPLETE";
278     case nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE:
279         return "ACTIVITY_SUBTYPE_TRANSACTION_CLOSE";
280 
281     case nsISocketTransport.STATUS_RESOLVING:
282         return "STATUS_RESOLVING";
283     case nsISocketTransport.STATUS_RESOLVED:
284         return "STATUS_RESOLVED";
285     case nsISocketTransport.STATUS_CONNECTING_TO:
286         return "STATUS_CONNECTING_TO";
287     case nsISocketTransport.STATUS_CONNECTED_TO:
288         return "STATUS_CONNECTED_TO";
289     case nsISocketTransport.STATUS_SENDING_TO:
290         return "STATUS_SENDING_TO";
291     case nsISocketTransport.STATUS_WAITING_FOR:
292         return "STATUS_WAITING_FOR";
293     case nsISocketTransport.STATUS_RECEIVING_FROM:
294         return "STATUS_RECEIVING_FROM";
295 
296     default:
297         return a;
298     }
299 }
300 
301 // ********************************************************************************************* //
302 
303 // https://bugzilla.mozilla.org/show_bug.cgi?id=669730
304 var HttpActivityObserverModule = Obj.extend(Firebug.Module,
305 {
306     dispatchName: "HttpActivityObserverModule",
307 
308     destroyContext: function(context)
309     {
310         this.cleanUp(context.window);
311     },
312 
313     unwatchWindow: function(context, win)
314     {
315         this.cleanUp(win);
316     },
317 
318     cleanUp: function(win)
319     {
320         for (var i=0; i<activeRequests.length; i+=2)
321         {
322             if (activeRequests[i+1] == win)
323             {
324                 activeRequests.splice(i, 2);
325                 i -= 2;
326             }
327         }
328     },
329 
330     shutdown: function()
331     {
332         // destroy NetHttpActivityObserver
333         NetHttpActivityObserver.unregisterObserver();
334         NetHttpActivityObserver.registerObserver = function() {};
335     }
336 });
337 
338 // ********************************************************************************************* //
339 // Registration
340 
341 Firebug.registerModule(HttpActivityObserverModule);
342 
343 return NetHttpActivityObserver;
344 
345 // ********************************************************************************************* //
346 });
347