blob: ba09fa9638335ac715ebb498c3838de5e5aabd03 [file] [log] [blame]
Jeff Thompson745026e2012-10-13 12:49:20 -07001/*
Jeff Thompson146d7de2012-11-17 16:15:28 -08002 * @author: Jeff Thompson
Jeff Thompson745026e2012-10-13 12:49:20 -07003 * See COPYING for copyright and distribution information.
4 */
5
Jeff Thompson08ab3cd2012-10-08 02:56:20 -07006var EXPORTED_SYMBOLS = ["ContentChannel"];
7
8const Cc = Components.classes;
9const Ci = Components.interfaces;
10const Cr = Components.results;
11
12Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
13
Jeff Thompson57d07382012-10-29 23:25:54 -070014/* Create an nsIChannel for returning content to the caller of asyncOpen.
15 * For requestContent detail, see asyncOpen.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070016 */
17function ContentChannel(uri, requestContent) {
18 this.requestContent = requestContent;
19
20 this.done = false;
21
Jeff Thompson60c95c82012-10-28 22:15:32 -070022 this.name = uri.spec;
Jeff Thompsonae95c2d2012-12-16 11:17:57 -080023 // Bit 18 "LOAD_REPLACE" means the window.location should use the URI set by onStart.
24 // loadFlags is updated by the caller of asyncOpen.
25 this.loadFlags = (1<<18);
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070026 this.loadGroup = null;
27 this.status = 200;
28
29 // We don't know these yet.
30 this.contentLength = -1;
31 this.contentType = null;
32 this.contentCharset = null;
33 this.URI = uri;
34 this.originalURI = uri;
35 this.owner = null;
36 this.notificationCallback = null;
37 this.securityInfo = null;
Jeff Thompson57d07382012-10-29 23:25:54 -070038
39 // Save the mostRecentWindow from the moment of creating the channel.
40 var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
41 this.mostRecentWindow = wm.getMostRecentWindow("navigator:browser");
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070042}
43
44ContentChannel.prototype = {
45 QueryInterface: function(aIID) {
46 if (aIID.equals(Ci.nsISupports))
47 return this;
48
49 if (aIID.equals(Ci.nsIRequest))
50 return this;
51
52 if (aIID.equals(Ci.nsIChannel))
53 return this;
54
55 throw Cr.NS_ERROR_NO_INTERFACE;
56 },
57
58 isPending: function() {
59 return !this.done;
60 },
61
62 cancel: function(aStatus){
63 this.status = aStatus;
64 this.done = true;
65 },
66
67 suspend: function(aStatus){
68 this.status = aStatus;
69 },
70
71 resume: function(aStatus){
72 this.status = aStatus;
73 },
74
75 open: function() {
76 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070077 }
78};
Jeff Thompson57d07382012-10-29 23:25:54 -070079
80/* Call requestContent(contentListener). When the content is available, you should call
Jeff Thompson8ed382a2012-11-04 08:05:21 -080081 * contentListener funtions as follows:
82 * onStart(contentType, contentCharset, uri)
83 * Set the contentType and contentCharset and call aListener.onStartRequest. If uri
84 * is not null, update this.URI and if this.loadFlags LOAD_INITIAL_DOCUMENT_URI bit is set,
85 * then update the URL bar of the mostRecentWindow. (Note that the caller of asyncOpen
86 * sets this.loadFlags.)
87 * onReceivedContent(content)
88 * Call aListener.onDataAvailable.
89 * onStop()
90 * Call aListener.onStopRequest.
Jeff Thompson57d07382012-10-29 23:25:54 -070091 */
92ContentChannel.prototype.asyncOpen = function(aListener, aContext) {
93 try {
94 var thisContentChannel = this;
95
96 var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
97 var callingThread = threadManager.currentThread;
98
99 var contentListener = {
Jeff Thompson8ed382a2012-11-04 08:05:21 -0800100 onStart : function(contentType, contentCharset, uri) {
Jeff Thompson57d07382012-10-29 23:25:54 -0700101 if (uri)
102 thisContentChannel.URI = uri;
Jeff Thompson57d07382012-10-29 23:25:54 -0700103 thisContentChannel.contentType = contentType;
104 thisContentChannel.contentCharset = contentCharset;
105
Jeff Thompson57d07382012-10-29 23:25:54 -0700106 // nsIChannel requires us to call aListener on its calling thread.
Jeff Thompson57d07382012-10-29 23:25:54 -0700107 callingThread.dispatch({
108 run: function() {
109 aListener.onStartRequest(thisContentChannel, aContext);
110 // Load flags bit 19 "LOAD_INITIAL_DOCUMENT_URI" means this channel is
111 // for the main window with the URL bar.
112 if (uri && thisContentChannel.loadFlags & (1<<19))
113 // aListener.onStartRequest may set the URL bar but now we update it.
114 thisContentChannel.mostRecentWindow.gURLBar.value =
115 thisContentChannel.URI.spec;
Jeff Thompson8ed382a2012-11-04 08:05:21 -0800116 }
117 }, 0);
118 },
119
120 onReceivedContent : function(content) {
121 var pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
122 pipe.init(true, true, 0, 0, null);
123 pipe.outputStream.write(content, content.length);
124 pipe.outputStream.close();
125
126 // nsIChannel requires us to call aListener on its calling thread.
127 // Assume calls to dispatch are eventually executed in order.
128 callingThread.dispatch({
129 run: function() {
Jeff Thompson57d07382012-10-29 23:25:54 -0700130 aListener.onDataAvailable(thisContentChannel, aContext,
131 pipe.inputStream, 0, content.length);
Jeff Thompson8ed382a2012-11-04 08:05:21 -0800132 }
133 }, 0);
134 },
135
136 onStop : function() {
137 thisContentChannel.done = true;
138
139 // nsIChannel requires us to call aListener on its calling thread.
140 callingThread.dispatch({
141 run: function() {
Jeff Thompson57d07382012-10-29 23:25:54 -0700142 aListener.onStopRequest(thisContentChannel, aContext,
143 thisContentChannel.status);
144 }
145 }, 0);
146 }
147 };
148
149 this.requestContent(contentListener);
150 } catch (ex) {
Jeff Thompson3cbf7462012-11-25 09:04:01 -0800151 dump("ContentChannel.asyncOpen exception: " + ex + "\n" + ex.stack);
Jeff Thompson57d07382012-10-29 23:25:54 -0700152 }
153};
154