blob: 4e83f106bbedff6388ff13df6bbdc7e428963ef8 [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;
23 // This is set by the caller of asyncOpen.
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070024 this.loadFlags = 0;
25 this.loadGroup = null;
26 this.status = 200;
27
28 // We don't know these yet.
29 this.contentLength = -1;
30 this.contentType = null;
31 this.contentCharset = null;
32 this.URI = uri;
33 this.originalURI = uri;
34 this.owner = null;
35 this.notificationCallback = null;
36 this.securityInfo = null;
Jeff Thompson57d07382012-10-29 23:25:54 -070037
38 // Save the mostRecentWindow from the moment of creating the channel.
39 var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
40 this.mostRecentWindow = wm.getMostRecentWindow("navigator:browser");
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070041}
42
43ContentChannel.prototype = {
44 QueryInterface: function(aIID) {
45 if (aIID.equals(Ci.nsISupports))
46 return this;
47
48 if (aIID.equals(Ci.nsIRequest))
49 return this;
50
51 if (aIID.equals(Ci.nsIChannel))
52 return this;
53
54 throw Cr.NS_ERROR_NO_INTERFACE;
55 },
56
57 isPending: function() {
58 return !this.done;
59 },
60
61 cancel: function(aStatus){
62 this.status = aStatus;
63 this.done = true;
64 },
65
66 suspend: function(aStatus){
67 this.status = aStatus;
68 },
69
70 resume: function(aStatus){
71 this.status = aStatus;
72 },
73
74 open: function() {
75 throw Cr.NS_ERROR_NOT_IMPLEMENTED;
Jeff Thompson08ab3cd2012-10-08 02:56:20 -070076 }
77};
Jeff Thompson57d07382012-10-29 23:25:54 -070078
79/* Call requestContent(contentListener). When the content is available, you should call
Jeff Thompson8ed382a2012-11-04 08:05:21 -080080 * contentListener funtions as follows:
81 * onStart(contentType, contentCharset, uri)
82 * Set the contentType and contentCharset and call aListener.onStartRequest. If uri
83 * is not null, update this.URI and if this.loadFlags LOAD_INITIAL_DOCUMENT_URI bit is set,
84 * then update the URL bar of the mostRecentWindow. (Note that the caller of asyncOpen
85 * sets this.loadFlags.)
86 * onReceivedContent(content)
87 * Call aListener.onDataAvailable.
88 * onStop()
89 * Call aListener.onStopRequest.
Jeff Thompson57d07382012-10-29 23:25:54 -070090 */
91ContentChannel.prototype.asyncOpen = function(aListener, aContext) {
92 try {
93 var thisContentChannel = this;
94
95 var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
96 var callingThread = threadManager.currentThread;
97
98 var contentListener = {
Jeff Thompson8ed382a2012-11-04 08:05:21 -080099 onStart : function(contentType, contentCharset, uri) {
Jeff Thompson57d07382012-10-29 23:25:54 -0700100 if (uri)
101 thisContentChannel.URI = uri;
Jeff Thompson57d07382012-10-29 23:25:54 -0700102 thisContentChannel.contentType = contentType;
103 thisContentChannel.contentCharset = contentCharset;
104
Jeff Thompson57d07382012-10-29 23:25:54 -0700105 // nsIChannel requires us to call aListener on its calling thread.
Jeff Thompson57d07382012-10-29 23:25:54 -0700106 callingThread.dispatch({
107 run: function() {
108 aListener.onStartRequest(thisContentChannel, aContext);
109 // Load flags bit 19 "LOAD_INITIAL_DOCUMENT_URI" means this channel is
110 // for the main window with the URL bar.
111 if (uri && thisContentChannel.loadFlags & (1<<19))
112 // aListener.onStartRequest may set the URL bar but now we update it.
113 thisContentChannel.mostRecentWindow.gURLBar.value =
114 thisContentChannel.URI.spec;
Jeff Thompson8ed382a2012-11-04 08:05:21 -0800115 }
116 }, 0);
117 },
118
119 onReceivedContent : function(content) {
120 var pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
121 pipe.init(true, true, 0, 0, null);
122 pipe.outputStream.write(content, content.length);
123 pipe.outputStream.close();
124
125 // nsIChannel requires us to call aListener on its calling thread.
126 // Assume calls to dispatch are eventually executed in order.
127 callingThread.dispatch({
128 run: function() {
Jeff Thompson57d07382012-10-29 23:25:54 -0700129 aListener.onDataAvailable(thisContentChannel, aContext,
130 pipe.inputStream, 0, content.length);
Jeff Thompson8ed382a2012-11-04 08:05:21 -0800131 }
132 }, 0);
133 },
134
135 onStop : function() {
136 thisContentChannel.done = true;
137
138 // nsIChannel requires us to call aListener on its calling thread.
139 callingThread.dispatch({
140 run: function() {
Jeff Thompson57d07382012-10-29 23:25:54 -0700141 aListener.onStopRequest(thisContentChannel, aContext,
142 thisContentChannel.status);
143 }
144 }, 0);
145 }
146 };
147
148 this.requestContent(contentListener);
149 } catch (ex) {
Jeff Thompson3cbf7462012-11-25 09:04:01 -0800150 dump("ContentChannel.asyncOpen exception: " + ex + "\n" + ex.stack);
Jeff Thompson57d07382012-10-29 23:25:54 -0700151 }
152};
153