fakePDS.js
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2010 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
25 if (typeof(Cc) == "undefined")
26  var Cc = Components.classes;
27 if (typeof(Ci) == "undefined")
28  var Ci = Components.interfaces;
29 if (typeof(Cr) == "undefined")
30  var Cr = Components.results;
31 if (typeof(Cu) == "undefined")
32  var Cu = Components.utils;
33 
35 {
36  _dialogClosing: false,
37 
38  _httpServer: null,
39  _httpServerPort: 8080,
40  _httpServerEnabled: false,
41  _httpServerRunning: false,
42  _httpServerRestart: false,
43 
44  _baseURL: "http://localhost:",
45 
46  _enableImageRequest: true,
47  _enableDLLRequest: true,
48  _enableDITRequest: true,
49 
50  _firmwareImageVersion: "1.0",
51  _firmwareImageFile: null,
52 
53  _firmwareDLLVersion: "1.0",
54  _firmwareDLLFile: null,
55 
56  _ditFile: null,
57 
58  _registeredImagePath: null,
59  _registeredDLLPath: null,
60  _registeredDITPath: null,
61 
62  _logRequestEnabled: false,
63  _logResponseEnabled: false,
64 
65  //
66  // Public Methods
67  //
68  onDialogLoad: function() {
69  this._httpServer = Cc["@mozilla.org/server/jshttp;1"]
70  .createInstance(Ci.nsIHttpServer);
71  },
72 
73  onDialogClose: function() {
74  this._httpServerEnabled = false;
75  this._dialogClosing = true;
76  this._overrideServer();
77  this._stopHttpServer();
78  return true;
79  },
80 
81  onEnableOverrideServer: function() {
82  var checkbox = document.getElementById("fakepds-override-server");
83  this._httpServerEnabled = checkbox.checked;
84  this._overrideServer();
85  this._restartHttpServer();
86  },
87 
88  onChangeOverrideServerPort: function() {
89  var textbox = document.getElementById("fakepds-override-server-port");
90  this._httpServerPort = parseInt(textbox.value);
91  this._restartHttpServer();
92  },
93 
94  onEnableFirmwareImageRequest: function() {
95  var checkbox = document.getElementById("fakepds-firmware-image-enabled");
96  this._enableImageRequest = checkbox.checked;
97  this._restartHttpServer();
98  },
99 
100  onEnableFirmwareDLLRequest: function() {
101  var checkbox = document.getElementById("fakepds-firmware-dll-enabled");
102  this._enableDLLRequest = checkbox.checked;
103  this._restartHttpServer();
104  },
105 
106  onChangeFirmwareImageVersion: function() {
107  var textbox = document.getElementById("fakepds-firmware-image-version");
108  this._firmwareImageVersion = textbox.value;
109  },
110 
111  onChangeFirmwareDLLVersion: function() {
112  var textbox = document.getElementById("fakepds-firmware-dll-version");
113  this._firmwareDLLVersion = textbox.value;
114  },
115 
116  onBrowseFirmwareImageFile: function() {
117  var file = this._openFilePicker("Choose Firmware Image",
118  null,
119  [{title: "Firmware Image Files", ext: "*.zip"}]);
120  if(file) {
121  var fileField = document.getElementById("fakepds-firmware-image-file");
122  fileField.file = file;
123 
124  this._firmwareImageFile = file;
125  }
126 
127  this._restartHttpServer();
128  },
129 
130  onBrowseFirmwareDLLFile: function() {
131  var file = this._openFilePicker("Choose Firmware DLL",
132  null,
133  [{title: "DLL or Zipped DLL", ext: "*.dll;*.zip"},
134  {title: "DLL Files", ext: "*.dll"},
135  {title: "ZIP Files", ext: "*.zip"}]);
136  if(file) {
137  var fileField = document.getElementById("fakepds-firmware-dll-file");
138  fileField.file = file;
139 
140  this._firmwareDLLFile = file;
141  }
142 
143  this._restartHttpServer();
144  },
145 
146  onEnableDITRequest: function() {
147  var checkbox = document.getElementById("fakepds-dit-enabled");
148  this._enableDITRequest = checkbox.checked;
149 
150  this._restartHttpServer();
151  },
152 
153  onBrowseDITFile: function() {
154  var file = this._openFilePicker("Choose a DIT",
155  Ci.nsIFilePicker.filterXML);
156  if(file) {
157  var fileField = document.getElementById("fakepds-dit-file");
158  fileField.file = file;
159 
160  this._ditFile = file;
161  }
162 
163  this._restartHttpServer();
164  },
165 
166  onEnableLogRequest: function() {
167  var checkbox = document.getElementById("fakepds-log-request-enabled");
168  this._logRequestEnabled = checkbox.checked;
169  },
170 
171  onEnableLogResponse: function() {
172  var checkbox = document.getElementById("fakepds-log-response-enabled");
173  this._logResponseEnabled = checkbox.checked;
174  },
175 
176  //
177  // nsIHttpServerStoppedCallback
178  //
179  onStopped: function() {
180  if(this._httpServerRestart) {
181  this._httpServerRestart = false;
182  this._startHttpServer();
183  return;
184  }
185 
186  if(this._dialogClosing) {
187  window.close();
188  return;
189  }
190  },
191 
192  //
193  // nsIHttpRequestHandler
194  //
195  handle: function(aRequest, aResponseData) {
196  this._parseRequest(aRequest, aResponseData);
197  },
198 
199  //
200  // Internal Methods
201  //
202  _startHttpServer: function() {
203  const requestPath = "/download_request";
204  const firmwareImagePath = "/firmware/image/";
205  const firmwareDLLPath = "/firmware/dll/";
206  const ditFilePath = "/dit/";
207 
208  if(this._httpServerRunning || !this._httpServerEnabled) {
209  return;
210  }
211 
212  this._httpServer.start(this._httpServerPort);
213  this._httpServer.registerPathHandler(requestPath, this);
214 
215  if(this._enableImageRequest && this._firmwareImageFile) {
216  let path = firmwareImagePath + this._firmwareImageFile.leafName;
217  this._httpServer.registerFile(path, this._firmwareImageFile);
218  this._registeredImagePath = path;
219  }
220 
221  if(this._enableDLLRequest && this._firmwareDLLFile) {
222  let path = firmwareDLLPath + this._firmwareDLLFile.leafName;
223  this._httpServer.registerFile(path, this._firmwareDLLFile);
224  this._registeredDLLPath = path;
225  }
226 
227  if(this._enableDITRequest && this._ditFile) {
228  let path = ditFilePath + this._ditFile.leafName;
229  this._httpServer.registerFile(path, this._ditFile);
230  this._registeredDITPath = path;
231  }
232 
233  this._httpServerRunning = true;
234  },
235 
236  _stopHttpServer: function() {
237  if(!this._httpServerRunning) {
238  if(this._httpServerRestart) {
239  this._httpServerRestart = false;
240  this._startHttpServer();
241  }
242  return;
243  }
244 
245  if(this._registeredImagePath) {
246  this._httpServer.registerFile(this._registeredImagePath, null);
247  this._registeredImagePath = null;
248  }
249 
250  if(this._registeredDLLPath) {
251  this._httpServer.registerFile(this._registeredDLLPath, null);
252  this._registeredDLLPath = null;
253  }
254 
255  if(this._registeredDITPath) {
256  this._httpServer.registerFile(this._registeredDITPath, null);
257  this._registeredDITPath = null;
258  }
259 
260  this._httpServer.stop(this);
261  this._httpServerRunning = false;
262  },
263 
264  _restartHttpServer: function() {
265  this._httpServerRestart = true;
266  this._stopHttpServer();
267  },
268 
269  _overrideServer: function() {
270  const overrideServerPref = "songbird.pds.override.url";
271  const prefs = Cc["@mozilla.org/fuel/application;1"]
272  .getService(Ci.fuelIApplication)
273  .prefs;
274 
275  if(this._httpServerEnabled) {
276  let url = "http://localhost:" +
277  this._httpServerPort +
278  "/download_request";
279 
280  prefs.setValue(overrideServerPref, url);
281  }
282  else {
283  let pref = prefs.get(overrideServerPref);
284  pref.reset();
285  }
286  },
287 
288  _openFilePicker: function(aTitle, aFilter, aFilterMap) {
289  var filePicker = Cc["@mozilla.org/filepicker;1"]
290  .createInstance(Ci.nsIFilePicker);
291  filePicker.init(window, aTitle, Ci.nsIFilePicker.modeOpen);
292 
293  if(aFilter) {
294  filePicker.appendFilters(aFilter);
295  }
296 
297  if(aFilterMap) {
298  for each (let filter in aFilterMap) {
299  filePicker.appendFilter(filter.title, filter.ext);
300  }
301  }
302 
303  if (filePicker.show() == Ci.nsIFilePicker.returnOK) {
304  return filePicker.file;
305  }
306 
307  return null;
308  },
309 
310  _parseRequest: function(aRequest, aResponseData) {
311  const dataToken = "data=";
312  // Only accept POST requests for 'download_request'.
313  if(aRequest.method != "POST") {
314  return this._invalidRequest(aResponseData);
315  }
316 
317  var inputStream = Cc["@mozilla.org/scriptableinputstream;1"]
318  .createInstance(Ci.nsIScriptableInputStream);
319  inputStream.init(aRequest.bodyInputStream);
320 
321  // We expect the full request data to be available.
322  var bytes = inputStream.available();
323  if(!bytes) {
324  return this._invalidRequest(aResponseData);
325  }
326 
327  // URI decode the body
328  var rawData = inputStream.read(bytes);
329  if(rawData.indexOf(dataToken) != 0) {
330  return this._invalidRequest(aResponseData);
331  }
332 
333  var uriDecodedData = decodeURIComponent(rawData.substr(dataToken.length));
334 
335  // Base 64 decode the body
336  var decodedData = window.atob(uriDecodedData);
337  this._logRequest(decodedData);
338 
339  // Load body into DOM parser
340  var parser = new DOMParser();
341  var requestXML = parser.parseFromString(decodedData, "text/xml");
342  if(requestXML.documentElement.nodeName != "DownloadRequest") {
343  return this._invalidRequest(aResponseData);
344  }
345 
346  // Find the request type
347  var requestType = null;
348  var children = requestXML.documentElement.childNodes;
349  for(let i = 0; i < children.length; i++) {
350  let childNode = children.item(i);
351  if(childNode.nodeName == "RequestType" &&
352  childNode.firstChild.nodeType == Node.TEXT_NODE) {
353  requestType = childNode.firstChild.nodeValue;
354  break;
355  }
356  }
357 
358  if(requestType == null) {
359  return this._invalidRequest(aResponseData);
360  }
361 
362  switch(requestType) {
363  case "HF1":
364  return this._handleFirmwareImageRequest(requestXML, aResponseData);
365  break;
366 
367  case "HF2":
368  return this._handleFirmwareRelNotesRequest(requestXML, aResponseData);
369  break;
370 
371  case "HF3":
372  return this._handleFirmwareDLLRequest(requestXML, aResponseData);
373  break;
374 
375  case "HF4":
376  return this._handleDITRequest(requestXML, aResponseData);
377  break;
378 
379  default:
380  return this._invalidRequest(aResponseData);
381  }
382  },
383 
384  _handleFirmwareImageRequest: function(aRequestXML, aResponseData) {
385  var pavctn = this._getPAVCTN(aRequestXML);
386  var requestVersion = this._getRequestVersion(aRequestXML);
387  var offerNewVersion =
388  this._compareVersions(requestVersion, this._firmwareImageVersion) < 0;
389 
390  if(!this._enableImageRequest || !this._registeredImagePath || !offerNewVersion) {
391  let responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
392  responseXML += "<PDSResponse>\n";
393  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
394  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
395  responseXML += " <DocType>HF1</DocType>\n";
396  responseXML += " <Response>NoDownloadAvailable</Response>\n";
397  responseXML += "</PDSResponse>\n";
398 
399  aResponseData.setStatusLine(null, 200, "OK");
400  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
401  this._logResponse(responseXML);
402  }
403  else if(this._enableImageRequest && this._registeredImagePath && offerNewVersion) {
404  let responseURL = this._baseURL +
405  this._httpServerPort +
406  this._registeredImagePath;
407 
408  let responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
409  responseXML += "<PDSResponse>\n";
410  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
411  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
412  responseXML += " <Response>DownloadAvailable</Response>\n";
413  responseXML += " <DocType>HF1</DocType>\n";
414  responseXML += " <Version>" + this._firmwareImageVersion + "</Version>\n";
415  responseXML += " <DownloadURL>" + responseURL + "</DownloadURL>\n";
416  responseXML += " <DocDesc>Firmware Image</DocDesc>\n";
417  responseXML += " <FileExtn>zip</FileExtn>\n";
418  responseXML += "</PDSResponse>\n";
419 
420  aResponseData.setStatusLine(null, 200, "OK");
421  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
422  this._logResponse(responseXML);
423  }
424  else {
425  this._invalidRequest(aResponseData);
426  }
427  },
428 
429  _handleFirmwareRelNotesRequest: function(aRequestXML, aResponseData) {
430  var pavctn = this._getPAVCTN(aRequestXML);
431  var responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
432  responseXML += "<PDSResponse>\n";
433  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
434  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
435  responseXML += " <DocType>HF2</DocType>\n";
436  responseXML += " <Response>NoDownloadAvailable</Response>\n";
437  responseXML += "</PDSResponse>\n";
438 
439  aResponseData.setStatusLine(null, 200, "OK");
440  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
441  this._logResponse(responseXML);
442  },
443 
444  _handleFirmwareDLLRequest: function(aRequestXML, aResponseData) {
445  var pavctn = this._getPAVCTN(aRequestXML);
446  if(!this._enableDLLRequest || !this._registeredDLLPath) {
447  let responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
448  responseXML += "<PDSResponse>\n";
449  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
450  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
451  responseXML += " <DocType>HF3</DocType>\n";
452  responseXML += " <Response>NoDownloadAvailable</Response>\n";
453  responseXML += "</PDSResponse>\n";
454 
455  aResponseData.setStatusLine(null, 200, "OK");
456  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
457  this._logResponse(responseXML);
458  }
459  else if(this._enableDLLRequest && this._registeredDLLPath) {
460  let responseURL = this._baseURL +
461  this._httpServerPort +
462  this._registeredDLLPath;
463 
464  let responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
465  responseXML += "<PDSResponse>\n";
466  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
467  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
468  responseXML += " <Response>DownloadAvailable</Response>\n";
469  responseXML += " <DocType>HF3</DocType>\n";
470  responseXML += " <Version>" + this._firmwareDLLVersion + "</Version>\n";
471  responseXML += " <DownloadURL>" + responseURL + "</DownloadURL>\n";
472  responseXML += " <DocDesc>Firmware Flashing DLL</DocDesc>\n";
473  responseXML += " <FileExtn>dll</FileExtn>\n";
474  responseXML += "</PDSResponse>\n";
475 
476  aResponseData.setStatusLine(null, 200, "OK");
477  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
478  this._logResponse(responseXML);
479  }
480  else {
481  this._invalidRequest(aResponseData);
482  }
483  },
484 
485  _handleDITRequest: function(aRequestXML, aResponseData) {
486  var pavctn = this._getPAVCTN(aRequestXML);
487  if(!this._enableDITRequest || !this._registeredDITPath) {
488  let responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
489  responseXML += "<PDSResponse>\n";
490  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
491  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
492  responseXML += " <DocType>HF4</DocType>\n";
493  responseXML += " <Response>NoDownloadAvailable</Response>\n";
494  responseXML += "</PDSResponse>\n";
495 
496  aResponseData.setStatusLine(null, 200, "OK");
497  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
498  this._logResponse(responseXML);
499  }
500  else if(this._enableDITRequest && this._registeredDITPath) {
501  let responseURL = this._baseURL +
502  this._httpServerPort +
503  this._registeredDITPath;
504 
505  let responseXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
506  responseXML += "<PDSResponse>\n";
507  responseXML += " <InterfaceId>PAV-SB-2K9-01</InterfaceId>\n";
508  responseXML += " <PAVCTN>" + pavctn + "</PAVCTN>\n";
509  responseXML += " <Response>DownloadAvailable</Response>\n";
510  responseXML += " <DocType>HF4</DocType>\n";
511  responseXML += " <Version>1.0</Version>\n";
512  responseXML += " <DownloadURL>" + responseURL + "</DownloadURL>\n";
513  responseXML += " <DocDesc>Device Information Table</DocDesc>\n";
514  responseXML += " <FileExtn>xml</FileExtn>\n";
515  responseXML += "</PDSResponse>\n";
516 
517  aResponseData.setStatusLine(null, 200, "OK");
518  aResponseData.bodyOutputStream.write(responseXML, responseXML.length);
519  this._logResponse(responseXML);
520  }
521  else {
522  // Invalid Request!
523  this._invalidRequest(aResponseData);
524  }
525  },
526 
527  _invalidRequest: function(aResponseData) {
528  const invalidRequestResponse = "Invalid Request Method";
529  aResponseData.setStatusLine(null, 405, "Method Not Allowed");
530  aResponseData.write(invalidRequestResponse);
531  this._logResponse(invalidRequestResponse);
532  },
533 
534  _getPAVCTN: function(aRequestXML) {
535  var documentElement = aRequestXML.documentElement;
536  var deviceVersion = documentElement.getElementsByTagName("DeviceVersion")
537  .item(0).firstChild.nodeValue;
538  var strokeNumber = documentElement.getElementsByTagName("StrokeNumber")
539  .item(0).firstChild.nodeValue;
540  var pavctn = deviceVersion + "/" + strokeNumber;
541 
542  return pavctn;
543  },
544 
545  _getRequestVersion: function(aRequestXML) {
546  var documentElement = aRequestXML.documentElement;
547  var currentVersion = documentElement.getElementsByTagName("CurrentVersion")
548  .item(0).firstChild.nodeValue;
549  return currentVersion;
550  },
551 
552  _compareVersions: function(aVersionA, aVersionB) {
553  var versionComparator = Cc["@mozilla.org/xpcom/version-comparator;1"]
554  .createInstance(Ci.nsIVersionComparator);
555  return versionComparator.compare(aVersionA, aVersionB);
556  },
557 
558  _logRequest: function(aRequestXML) {
559  if(this._logRequestEnabled) {
560  const console = Cc["@mozilla.org/fuel/application;1"]
561  .getService(Ci.fuelIApplication)
562  .console;
563  console.log("Fake PDS Request:\n" + aRequestXML);
564  }
565  },
566 
567  _logResponse: function(aResponseXML) {
568  if(this._logResponseEnabled) {
569  const console = Cc["@mozilla.org/fuel/application;1"]
570  .getService(Ci.fuelIApplication)
571  .console;
572  console.log("Fake PDS Response:\n" + aResponseXML);
573  }
574  },
575 };
var DialogController
Definition: fakePDS.js:34
const Cu
const Cc
var pref
Definition: openLocation.js:44
function handle(request, response)
let window
return null
Definition: FeedWriter.js:1143
function url(spec)
var prefs
Definition: FeedWriter.js:1169
const Cr
const Ci
_getSelectedPageStyle s i
Array filter(tab.attributes, function(aAttr){return(_this.xulAttributes.indexOf(aAttr.name) >-1);}).forEach(tab.removeAttribute
var file