1 /* See license.txt for terms of usage */
  2 
  3 define([
  4     "firebug/lib/xpcom",
  5     "firebug/lib/trace",
  6     "firebug/lib/string",
  7     "firebug/lib/http",
  8     "firebug/trace/traceModule",
  9     "firebug/trace/traceListener"
 10 ],
 11 function(Xpcom, FBTrace, Str, Http, TraceModule, TraceListener) {
 12 
 13 // ********************************************************************************************* //
 14 // Constants
 15 
 16 const Cc = Components.classes;
 17 const Ci = Components.interfaces;
 18 const Cr = Components.results;
 19 
 20 var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
 21 var categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
 22 
 23 // ********************************************************************************************* //
 24 // HTTP Request Observer implementation
 25 
 26 /**
 27  * @service This service is intended as the only HTTP observer registered by Firebug.
 28  * All FB extensions and Firebug itself should register a listener within this
 29  * service in order to listen for http-on-modify-request, http-on-examine-response and
 30  * http-on-examine-cached-response events.
 31  *
 32  * See also: <a href="http://developer.mozilla.org/en/Setting_HTTP_request_headers">
 33  * Setting_HTTP_request_headers</a>
 34  */
 35 var HttpRequestObserver =
 36 /** lends HttpRequestObserver */
 37 {
 38     observers: [],
 39     observing: false,
 40 
 41     registerObservers: function()
 42     {
 43         if (FBTrace.DBG_HTTPOBSERVER)
 44             FBTrace.sysout("httpObserver.registerObservers; (" + this.observers.length + "), " +
 45                 "active: " + this.observing, getObserverList());
 46 
 47         if (!this.observing)
 48         {
 49             observerService.addObserver(this, "http-on-opening-request", false);
 50             observerService.addObserver(this, "http-on-modify-request", false);
 51             observerService.addObserver(this, "http-on-examine-response", false);
 52             observerService.addObserver(this, "http-on-examine-cached-response", false);
 53         }
 54 
 55         this.observing = true;
 56     },
 57 
 58     unregisterObservers: function()
 59     {
 60         if (FBTrace.DBG_HTTPOBSERVER)
 61             FBTrace.sysout("httpObserver.unregisterObservers; (" + this.observers.length + "), " +
 62                 "active: " + this.observing, getObserverList());
 63 
 64         if (this.observing)
 65         {
 66             observerService.removeObserver(this, "http-on-opening-request");
 67             observerService.removeObserver(this, "http-on-modify-request");
 68             observerService.removeObserver(this, "http-on-examine-response");
 69             observerService.removeObserver(this, "http-on-examine-cached-response");
 70         }
 71 
 72         this.observing = false;
 73     },
 74 
 75     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 76     // nsIObserver
 77 
 78     observe: function(subject, topic, data)
 79     {
 80         try
 81         {
 82             if (!(subject instanceof Ci.nsIHttpChannel))
 83                 return;
 84 
 85             // Notify all registered observers.
 86             if (topic == "http-on-modify-request" ||
 87                 topic == "http-on-examine-response" ||
 88                 topic == "http-on-examine-cached-response" ||
 89                 topic == "http-on-opening-request")
 90             {
 91                 this.notifyObservers(subject, topic, data);
 92             }
 93         }
 94         catch (err)
 95         {
 96             if (FBTrace.DBG_ERRORS)
 97                 FBTrace.sysout("httpObserver.observe EXCEPTION", err);
 98         }
 99     },
100 
101     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
102     // nsIObserverService
103 
104     addObserver: function(observer, topic, weak)
105     {
106         if (!topic)
107             topic = "firebug-http-event";
108 
109         if (topic != "firebug-http-event")
110             throw Cr.NS_ERROR_INVALID_ARG;
111 
112         // Do not add an observer twice.
113         for (var i=0; i<this.observers.length; i++)
114         {
115             if (this.observers[i] == observer)
116             {
117                 // xxxHonza: firebug/debugger is registering itself more times,
118                 // not sure if it's on purpose, but it causes following error message:
119                 // Error: attempt to run compile-and-go script on a cleared scope
120                 // (on the first line of the observe method)
121                 if (FBTrace.DBG_HTTPOBSERVER)
122                     FBTrace.sysout("httpObserver.addObserver; ERROR? Observer already registered: " +
123                         observer.dispatchName, getObserverList());
124                 return;
125             }
126         }
127 
128         this.observers.push(observer);
129 
130         if (FBTrace.DBG_HTTPOBSERVER)
131             FBTrace.sysout("httpObserver.addObserver; (" + this.observers.length +
132                 "), added: " + observer.dispatchName);
133 
134         if (this.observers.length > 0)
135             this.registerObservers();
136     },
137 
138     removeObserver: function(observer, topic)
139     {
140         if (!topic)
141             topic = "firebug-http-event";
142 
143         if (topic != "firebug-http-event")
144             throw Cr.NS_ERROR_INVALID_ARG;
145 
146         for (var i=0; i<this.observers.length; i++)
147         {
148             if (this.observers[i] == observer)
149             {
150                 this.observers.splice(i, 1);
151 
152                 if (this.observers.length == 0)
153                     this.unregisterObservers();
154 
155                 if (FBTrace.DBG_HTTPOBSERVER)
156                     FBTrace.sysout("httpObserver.removeObserver; (" + this.observers.length +
157                         "), removed: " + observer.dispatchName, getObserverList());
158                 return;
159             }
160         }
161 
162         if (FBTrace.DBG_HTTPOBSERVER)
163             FBTrace.sysout("httpObserver.removeObserver ERROR? (no such observer): " +
164                 observer.dispatchName);
165     },
166 
167     notifyObservers: function(subject, topic, data)
168     {
169         if (FBTrace.DBG_HTTPOBSERVER)
170         {
171             FBTrace.sysout("httpObserver.notifyObservers (" + this.observers.length + ") " +
172                 (topic ? topic.toUpperCase() : topic) + ", " + Http.safeGetRequestName(subject),
173                 getObserverList());
174         }
175 
176         for (var i=0; i<this.observers.length; i++)
177         {
178             var observer = this.observers[i];
179             try
180             {
181                 if (observer.observe)
182                     observer.observe(subject, topic, data);
183             }
184             catch (err)
185             {
186                 if (FBTrace.DBG_HTTPOBSERVER)
187                     FBTrace.sysout("httpObserver.notifyObservers; EXCEPTION " + err, err);
188             }
189         }
190     }
191 }
192 
193 // ********************************************************************************************* //
194 // Tracing Support
195 
196 function getObserverList()
197 {
198     var observerNames = [];
199     for (var i=0; i<HttpRequestObserver.observers.length; i++)
200         observerNames.push(HttpRequestObserver.observers[i].dispatchName);
201 
202     return observerNames;
203 }
204 
205 // ********************************************************************************************* //
206 // Registration
207 
208 // Compatibility with Firebug 1.7 extensions: deprecated, obsolete
209 FBL.httpObserver = HttpRequestObserver;
210 
211 // xxxHonza: Do we need to remove the listener?
212 TraceModule.addListener(new TraceListener("httpObserver.", "DBG_HTTPOBSERVER", true));
213 
214 return HttpRequestObserver;
215 
216 // ********************************************************************************************* //
217 });
218