1 /* See license.txt for terms of usage */
  2 
  3 // ********************************************************************************************* //
  4 // Constants
  5 
  6 const Cc = Components.classes;
  7 const Ci = Components.interfaces;
  8 const Cr = Components.results;
  9 const Cu = Components.utils;
 10 
 11 var EXPORTED_SYMBOLS = ["httpRequestObserver"];
 12 
 13 var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
 14 var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
 15 
 16 Cu["import"]("resource://firebug/fbtrace.js");
 17 
 18 // ********************************************************************************************* //
 19 // HTTP Request Observer implementation
 20 
 21 /**
 22  * @service This service is intended as the only HTTP observer registered by Firebug.
 23  * All FB extensions and Firebug itself should register a listener within this
 24  * service in order to listen for http-on-modify-request, http-on-examine-response and
 25  * http-on-examine-cached-response events.
 26  *
 27  * See also: <a href="http://developer.mozilla.org/en/Setting_HTTP_request_headers">
 28  * Setting_HTTP_request_headers</a>
 29  */
 30 var httpRequestObserver =
 31 /** lends HttpRequestObserver */
 32 {
 33     preInitialize: function()
 34     {
 35         this.observers = [];
 36         this.observing = 0;
 37         this.initialize();
 38     },
 39 
 40     initialize: function()
 41     {
 42         observerService.addObserver(this, "quit-application", false);
 43 
 44         if (FBTrace.DBG_HTTPOBSERVER)
 45             FBTrace.sysout("httpObserver.initialize OK");
 46     },
 47 
 48     shutdown: function()
 49     {
 50         observerService.removeObserver(this, "quit-application");
 51 
 52         if (FBTrace.DBG_HTTPOBSERVER)
 53             FBTrace.sysout("httpObserver.shutdown OK");
 54     },
 55 
 56     registerObservers: function()
 57     {
 58         if (FBTrace.DBG_HTTPOBSERVER)
 59             FBTrace.sysout("httpObserver.registerObservers; wasObserving: " +
 60                 this.observing + " with observers "+this.observers.length, this.observers);
 61 
 62         if (!this.observing)
 63         {
 64             observerService.addObserver(this, "http-on-opening-request", false);
 65             observerService.addObserver(this, "http-on-modify-request", false);
 66             observerService.addObserver(this, "http-on-examine-response", false);
 67             observerService.addObserver(this, "http-on-examine-cached-response", false);
 68         }
 69 
 70         this.observing = true;
 71     },
 72 
 73     unregisterObservers: function()
 74     {
 75         if (FBTrace.DBG_HTTPOBSERVER)
 76             FBTrace.sysout("httpObserver.unregisterObservers; wasObserving: " +
 77                 this.observing + " with observers "+this.observers.length, this.observers);
 78 
 79         if (this.observing)
 80         {
 81             observerService.removeObserver(this, "http-on-opening-request");
 82             observerService.removeObserver(this, "http-on-modify-request");
 83             observerService.removeObserver(this, "http-on-examine-response");
 84             observerService.removeObserver(this, "http-on-examine-cached-response");
 85         }
 86 
 87         this.observing = false;
 88     },
 89 
 90     /* nsIObserve */
 91     observe: function(subject, topic, data)
 92     {
 93         if (topic == "quit-application")
 94         {
 95             this.shutdown();
 96             return;
 97         }
 98 
 99         try
100         {
101             if (!(subject instanceof Ci.nsIHttpChannel))
102                 return;
103 
104             if (FBTrace.DBG_HTTPOBSERVER)
105                 FBTrace.sysout("httpObserver.observe " + (topic ? topic.toUpperCase() : topic) +
106                     ", " + safeGetName(subject));
107 
108             // Notify all registered observers.
109             if (topic == "http-on-opening-request" ||
110                 topic == "http-on-modify-request" ||
111                 topic == "http-on-examine-response" ||
112                 topic == "http-on-examine-cached-response")
113             {
114                 this.notifyObservers(subject, topic, data);
115             }
116         }
117         catch (err)
118         {
119             if (FBTrace.DBG_ERRORS)
120                 FBTrace.sysout("httpObserver.observe EXCEPTION", err);
121         }
122     },
123 
124     /* nsIObserverService */
125     addObserver: function(observer, topic, weak)
126     {
127         if (!topic)
128             topic = "firebug-http-event";
129 
130         if (topic != "firebug-http-event")
131             throw Cr.NS_ERROR_INVALID_ARG;
132 
133         this.observers.push(observer);
134 
135         if (this.observers.length > 0)
136             this.registerObservers();
137     },
138 
139     removeObserver: function(observer, topic)
140     {
141         if (!topic)
142             topic = "firebug-http-event";
143 
144         if (topic != "firebug-http-event")
145             throw Cr.NS_ERROR_INVALID_ARG;
146 
147         for (var i=0; i<this.observers.length; i++)
148         {
149             if (this.observers[i] == observer)
150             {
151                 this.observers.splice(i, 1);
152 
153                 if (this.observers.length == 0)
154                     this.unregisterObservers();
155 
156                 return;
157             }
158         }
159 
160         if (FBTrace.DBG_HTTPOBSERVER)
161             FBTrace.sysout("httpObserver.removeObserver FAILED (no such observer)");
162     },
163 
164     notifyObservers: function(subject, topic, data)
165     {
166         if (FBTrace.DBG_HTTPOBSERVER)
167             FBTrace.sysout("httpObserver.notifyObservers (" + this.observers.length + ") " + topic);
168 
169         for (var i=0; i<this.observers.length; i++)
170         {
171             var observer = this.observers[i];
172             try
173             {
174                 if (observer.observe)
175                     observer.observe(subject, topic, data);
176             }
177             catch (err)
178             {
179                 if (FBTrace.DBG_HTTPOBSERVER)
180                     FBTrace.sysout("httpObserver.notifyObservers; EXCEPTION " + err, err);
181             }
182         }
183     }
184 }
185 
186 // ********************************************************************************************* //
187 // Request helpers
188 
189 function safeGetName(request)
190 {
191     try
192     {
193         return request.name;
194     }
195     catch (exc)
196     {
197     }
198 
199     return null;
200 }
201 
202 // ********************************************************************************************* //
203 // Debugging Helpers
204 
205 function dumpStack(message)
206 {
207     dump(message + "\n");
208 
209     for (var frame = Components.stack, i = 0; frame; frame = frame.caller, i++)
210     {
211         if (i < 1)
212             continue;
213 
214         var fileName = unescape(frame.filename ? frame.filename : "");
215         var lineNumber = frame.lineNumber ? frame.lineNumber : "";
216 
217         dump(fileName + ":" + lineNumber + "\n");
218     }
219 }
220 
221 // ********************************************************************************************* //
222 // Initialization
223 
224 httpRequestObserver.preInitialize();
225 
226 // ********************************************************************************************* //
227