summaryrefslogtreecommitdiffabout
path: root/src/components
Unidiff
Diffstat (limited to 'src/components') (more/less context) (ignore whitespace changes)
-rwxr-xr-xsrc/components/xriProtocolHandler.js1060
1 files changed, 1060 insertions, 0 deletions
diff --git a/src/components/xriProtocolHandler.js b/src/components/xriProtocolHandler.js
new file mode 100755
index 0000000..7046cde
--- a/dev/null
+++ b/src/components/xriProtocolHandler.js
@@ -0,0 +1,1060 @@
1/***********************************************************
2 constants
3 ***********************************************************/
4
5// The interface we implement - nsIProtocolHandler
6const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler;
7
8// Interfaces that we require
9 const nsISupports = Components.interfaces.nsISupports;
10 const nsIIOService = Components.interfaces.nsIIOService;
11 const nsIURI = Components.interfaces.nsIURI;
12 const nsIURL = Components.interfaces.nsIURL;
13 const nsIRequest = Components.interfaces.nsIRequest;
14const nsIRequestObserver = Components.interfaces.nsIRequestObserver;
15 const nsIChannel = Components.interfaces.nsIChannel;
16 const nsIHttpChannel = Components.interfaces.nsIHttpChannel;
17 const nsIStreamListener = Components.interfaces.nsIStreamListener;
18
19
20// UUID uniquely identifying our component
21// You can get from: http://kruithof.xs4all.nl/uuid/uuidgen here
22const CLASS_ID = Components.ID("{ea00b610-215a-11db-a98b-0800200c9a66}");
23
24// textual unique identifier
25const CONTRACT_ID = "@mozilla.org/network/protocol;1?name=xri";
26
27// Components that we require
28const CID_URI = "@mozilla.org/network/simple-uri;1";
29const kIOSERVICE_CID_STR = "{9ac9e770-18bc-11d3-9337-00104ba0fd40}";
30const CID_URL = "@mozilla.org/network/standard-url;1";
31
32// description
33const CLASS_NAME = "XRI Protocol Handler";
34
35const PROXY_URI = "http://xri.net/";
36
37const XP_ANY_TYPE = 0;
38const XP_NUMBER_TYPE = 1;
39const XP_STRING_TYPE = 2;
40const XP_BOOLEAN_TYPE = 3;
41const XP_UNORDERED_NODE_ITERATOR_TYPE = 4;
42const XP_ORDERED_NODE_ITERATOR_TYPE = 5;
43const XP_UNORDERED_NODE_SNAPSHOT_TYPE = 6;
44const XP_ORDERED_NODE_SNAPSHOT_TYPE = 7;
45const XP_ANY_UNORDERED_NODE_TYPE = 8;
46const XP_FIRST_ORDERED_NODE_TYPE = 9;
47
48
49var SERVICE_CLASSES = {
50 'xri://+i-service*(+contact)*($v*1.0)': 'i-contact',
51 'http://openid.net/signon/1.0': 'openid',
52 'xri://$res*auth*($v*2.0)': 'res-auth',
53 'xri://+i-service*(+authn)*(+saml)*($v*1.0)': 'authn-saml',
54 'xri://+i-service*(+metadata)*(+saml)*($v*1.0)' : 'metadata-saml',
55 'xri://+i-service*(+forwarding)*($v*1.0)': 'i-forwarding'
56};
57
58
59const HTML_HEAD = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\
60 <html xmlns=\"http://www.w3.org/1999/xhtml\">\n\
61 <head>\n\
62 <title>FoXRI Explorer - #QXRI#</title>\n\
63 <link href=\"chrome://foxri/content/foxri_explorer.css\" rel=\"stylesheet\" type=\"text/css\" />\n\
64 <body>\n\
65 <h1>FoXRI Explorer</h1>\n\
66 <div id=\"explorer_body\">\n";
67
68const HTML_FOOT = "</div>\n\
69 </body>\n\
70 </html>";
71
72
73
74/// Generic object method wrapper
75function methodWrapper(obj, method)
76{
77 return (
78 function() {
79 /* pass it this inner closure's arguments */
80 obj[method](arguments);
81 }
82 );
83}
84
85
86
87/// XRDS utility functions
88
89
90var nsResolver = {
91 lookupNamespaceURI: function(prefix)
92 {
93 if (prefix == "xrds")
94 return "xri://$xrds";
95 else if (prefix == "xrd")
96 return "xri://$xrd*($v*2.0)";
97 return "";
98 }
99};
100
101
102
103function runExpr(doc, context, expr, returnType)
104{
105 if (!returnType)
106 returnType = XP_ANY_TYPE;
107 var res = doc.evaluate(expr, context, nsResolver, returnType, null);
108 return res;
109}
110
111
112function getNumeric(doc, context, expr)
113{
114 var res = runExpr(doc, context, expr, XP_NUMBER_TYPE);
115 if (res)
116 return res.numberValue;
117 return null;
118}
119
120
121function getString(doc, context, expr)
122{
123 // var res = runExpr(doc, context, expr, XPathResult.STRING_TYPE);
124 var res = runExpr(doc, context, expr, XP_STRING_TYPE);
125 if (res)
126 return res.stringValue;
127 return null;
128}
129
130function getNode(doc, context, expr)
131{
132 var res = runExpr(doc, context, expr, XP_FIRST_ORDERED_NODE_TYPE);
133 if (res)
134 return res.singleNodeValue;
135 return null;
136}
137
138
139function getFinalXRD(doc)
140{
141 var lastNode = doc.firstChild;
142 while (true) {
143 var node = getNode(doc, lastNode, "xrds:XRDS[position()=last()]");
144 if (!node)
145 break;
146 lastNode = node;
147 }
148
149 return getNode(doc, lastNode, "xrd:XRD[position()=last()]");
150}
151
152
153function isIName(xri)
154{
155 if (xri.match('^xri://.!', 'i')) {
156 return false;
157 }
158 if (xri.match('^.!', 'i')) {
159 return false;
160 }
161 return true;
162}
163
164
165function arraySearch(a, re)
166{
167 var returnArr = new Array();
168 var i;
169 for (i = 0; i < a.length; i++) {
170 if (a[i].match(re)) {
171 returnArr.push(a[i]);
172 }
173 }
174
175 return returnArr;
176}
177
178
179function renderService(srv, doc, qxri)
180{
181 var html_types = '';
182 var html_paths = '';
183 var html_mediatypes = '';
184 var html_uris = '';
185 var html_actions = '';
186
187 var serviceName = friendlyServiceName(null);
188 var serviceType; // the last non-null Type
189 var knownServiceType; // first recognized service type
190
191 // get the types
192 var res = runExpr(doc, srv, "xrd:Type/text()");
193 var t;
194 while (t = res.iterateNext()) {
195 if (t.nodeValue) {
196 if (!knownServiceType && isKnownServiceType(t.nodeValue)) {
197 knownServiceType = t.nodeValue;
198 }
199
200 serviceType = t.nodeValue;
201 html_types += "<strong>Type:</strong> " + t.nodeValue + "<br/>";
202 }
203 }
204
205 // get the paths
206 res = runExpr(doc, srv, "xrd:Path/text()");
207 var p;
208 var qxri_prefix = qxri;
209 if (qxri_prefix.charAt(qxri_prefix.length - 1) != '/') {
210 qxri_prefix += '/';
211 }
212
213 while (p = res.iterateNext()) {
214 if (p.nodeValue) {
215 html_paths += "<strong>Path:</strong> " + p.nodeValue
216 + " [ <tt><a href=\"" + qxri_prefix + p.nodeValue + "\">"
217 + qxri_prefix + p.nodeValue + "</a></tt> ]"
218 + "<br/>\n";
219 }
220 }
221
222
223 // get the mediatypes
224 mediaTypes = new Array();
225 res = runExpr(doc, srv, "xrd:MediaType/text()");
226 var m;
227 while (m = res.iterateNext()) {
228 if (!knownServiceType) {
229 var srvType = guessServiceTypeByMime(m.nodeValue);
230 knownServiceType = srvType? srvType : null;
231 }
232
233 mediaTypes.push(m.nodeValue);
234 if (m.nodeValue) {
235 html_mediatypes += "<strong>Media Type:</strong> " + m.nodeValue + "<br/>";
236 }
237 }
238
239
240 res = runExpr(doc, srv, "xrd:URI/text()");
241 var u;
242 while (u = res.iterateNext()) {
243 if (!u.nodeValue)
244 continue;
245
246 var srvType = guessServiceTypeByURI(u.nodeValue);
247 if (!knownServiceType) {
248 knownServiceType = srvType;
249 }
250
251 html_uris += "<div class=\"" + getServiceClass(srvType) + "\">";
252
253 var linkContent = u.nodeValue;
254 var uriParts = u.nodeValue.match('^(.*):(.*)$');
255 if (!uriParts)
256 continue;
257
258 if (uriParts[1] == 'data') {
259 uriParts = uriParts[2].match('^(.*/.*),(.*)');
260 if (uriParts && uriParts[1].match('^image/', 'i')) {
261 linkContent = "<img src=\"" + u.nodeValue + "\"/>";
262 }
263 else if (uriParts) {
264 linkContent = uriParts[1] + " data";
265 }
266 }
267 else if (uriParts[1] == 'skype') {
268 uriParts = uriParts[2].match('^(.*)\\?(.*)');
269 if (uriParts) {
270 if (uriParts[2] == "call") {
271 linkContent = "<img src=\"chrome://foxri/content/skype_call_large.png\" alt=\"Call " + uriParts[1] + "\"/>";
272 }
273 else if (uriParts[2] == "chat") {
274 linkContent = "<img src=\"chrome://foxri/content/skype_chat_large.png\" alt=\"Chat with " + uriParts[1] + "\"/>";
275 }
276 else if (uriParts[2] == "add") {
277 linkContent = "<img src=\"chrome://foxri/content/skype_add_large.png\" alt=\"Add " + uriParts[1] + " to Skype\"/>";
278 }
279 }
280 }
281 else if (uriParts[1] == 'aim') {
282 uriParts = uriParts[2].match('^(.*)\\?.*screenname=([^&]*)', 'i');
283 if (uriParts) {
284 linkContent = "<img src=\"chrome://foxri/content/aim_logo.gif\" alt=\"Chat with " + uriParts[2] + "\"/> Chat with " + uriParts[2];
285 }
286 }
287
288 html_uris += "<a href=\""+u.nodeValue+"\">"
289 + linkContent + "</a>";
290 html_uris += "</div>";
291 }
292
293 var html = "<div class=\"service srv_" + getServiceClass(knownServiceType) + "\">\n";
294 html += html_types;
295 html += html_paths;
296 html += html_mediatypes;
297 if (html_uris) {
298 html += "<strong>URI(s):</strong><br/>\n";
299 html += html_uris;
300 }
301 html += "</div>";
302
303 return html;
304}
305
306
307
308function isKnownServiceType(type)
309{
310 if (type.toLowerCase() in SERVICE_CLASSES) {
311 return true;
312 }
313 return false;
314}
315
316function getServiceClass(type)
317{
318 if (isKnownServiceType(type)) {
319 return SERVICE_CLASSES[type.toLowerCase()];
320 }
321 return type;
322}
323
324
325function guessServiceTypeByURI(uri)
326{
327 if (uri == null || uri == "") {
328 return "unknown";
329 }
330 if (uri.match(/^https?:/i)) {
331 return "www";
332 }
333 else if (uri.match(/^skype:/i)) {
334 return "skype";
335 }
336 else if (uri.match(/^aim:/i)) {
337 return "aim";
338 }
339 else if (uri.match(/^xmpp:/i)) {
340 return "jabber";
341 }
342 else if (uri.match(/^tel:/i)) {
343 return "tel";
344 }
345 else if (uri.match(/^callto:/i)) {
346 return "callto";
347 }
348 else if (uri.match(/^telnet:/i)) {
349 return "telnet";
350 }
351 else if (uri.match(/^news:/i)) {
352 return "news";
353 }
354 else if (uri.match(/^nntp:/i)) {
355 return "nntp";
356 }
357 else if (uri.match(/^ftp:/i)) {
358 return "ftp";
359 }
360 else if (uri.match(/^mailto:/i)) {
361 return "email";
362 }
363 else if (uri.match(/^urn:/i)) {
364 return "urn";
365 }
366 else if (uri.match(/^data:/i)) {
367 return "data";
368 }
369 else if (uri.match(/^feed:/i)) {
370 return "feed";
371 }
372 return "unknown";
373}
374
375
376function guessServiceTypeByMime(mimeType)
377{
378 if (mimeType.match(/^application\/(rss|atom)\+xml/i)) {
379 dump("feed detected!\n");
380 return "feed";
381 }
382 else if (mimeType.match(/^image\//i)) {
383 return "image";
384 }
385 return null;
386}
387
388
389
390function friendlyServiceName(srvType, uri)
391{
392 if (srvType && srvType == "xri://+i-service*(+contact)*($v*1.0)") {
393 return "Contact Service";
394 }
395 else if (srvType && srvType == "http://openid.net/signon/1.0") {
396 return "OpenID Authentication Service";
397 }
398 else if (srvType && srvType == "xri://$res*auth*($v*2.0)") {
399 return "Authority Resolution Service";
400 }
401 else {
402 if (uri == null) {
403 return "Generic Service";
404 }
405 if (uri.match(/^https?:/i)) {
406 return "Web Link";
407 }
408 else if (uri.match(/^skype:/i)) {
409 var user = uri.substring("skype:".length, uri.indexOf('?'));
410 return "Skype <a href=\"" + uri + "\"><img src=\"chrome://foxri/content/skype_call.png\"></a>";
411 }
412 else if (uri.match(/^mailto:/i)) {
413 var qmark = uri.indexOf('?');
414 var email = (qmark == -1)?
415 uri.substr("mailto:".length) :
416 uri.substring("mailto:".length, qmark);
417 return "Email (address: " + email + ")";
418 }
419 else if (srvType != null) {
420 return srvType; // return verbatim
421 }
422 return "Generic Service";
423 }
424}
425
426
427
428
429function subHTML(template, vars)
430{
431 for (key in vars) {
432 template = template.replace(key, vars[key], 'g');
433 }
434 return template;
435}
436
437
438/// Given the completed XMLHttpRequest object, renders the XRDS
439function renderXRDS(xmlDoc)
440{
441 var x = xmlDoc;
442 var qxri = getString(x, x, "/xrds:XRDS/@ref");
443
444 var html = subHTML(HTML_HEAD, { '#QXRI#': qxri });
445
446 // TODO: render parents as well
447
448 var lastNode = getFinalXRD(x);
449 if (lastNode) {
450 var stat = getString(x, lastNode, "xrd:Status/@code");
451 if (stat == "100") {
452 html += "<h3>Exploring <strong>" + qxri + "</strong></h3>";
453 }
454 else {
455 var msg = getString(x, lastNode, "xrd:Status/text()");
456 html += "<h3 class=\"error\"><strong>" + qxri + "</strong> failed to resolve (reason: " + stat + " - " + msg + ")</h3>";
457 }
458
459 html += "<br/>";
460
461 var services = runExpr(x, lastNode, "xrd:Service");
462 var s;
463 var count = getNumeric(x, lastNode, "count(xrd:Service)");
464 if (count > 0) {
465 while (s = services.iterateNext()) {
466 count++;
467 html += renderService(s, x, qxri);
468 }
469 }
470 else if (stat == '222') {
471 var xriType = isIName(qxri)? 'I-name' : 'I-number';
472 html += "<p class='error'>" + xriType + " does not exist.</p>\n";
473 }
474 else {
475 html += "<p>No service has been configured for this XRI</p>";
476 }
477
478 }
479
480 html += "</html>";
481
482 return html;
483}
484
485
486
487
488
489
490/***********************************************************
491 XriServiceExplorer class definition
492 ***********************************************************/
493
494
495function XRIChannel(uri) {
496 this.URI = uri;
497 var r = uri.spec.indexOf('#');
498 if (r >= 0) {
499 this.qxri = uri.spec.substring(0, r);
500 this.fragment = uri.spec.substring(r);
501 }
502 else {
503 this.qxri = uri.spec;
504 }
505};
506
507
508XRIChannel.prototype = {
509
510 fragment: null,
511
512/* private fields used internally */
513 qxri: null,
514
515 xmlRequest: null,
516
517 renderedHTML: null,
518
519 scriptableInStream: null,
520
521 buf: null,
522
523 mChannel: null,
524
525
526 copyFields: function(request)
527 {
528 dump("copyFields(loadFlags=" + request.loadFlags + ")\n");
529 dump("loadGroup = " + request.loadGroup + "\n");
530 dump("notificationCallbacks = " + request.notificationCallbacks + "\n");
531
532 // copy request fields
533 this.loadFlags = request.loadFlags;
534 this.loadGroup = request.loadGroup;
535 this.name = request.name;
536 this.status = request.status;
537
538 var channel = request.QueryInterface(nsIChannel);
539 if (channel) {
540 this.contentCharset = channel.contentCharset;
541 this.contentLength = channel.contentLength;
542 this.contentType = channel.contentType; // XXX
543 this.contentType = "text/html";
544 this.notificationCallbacks = channel.notificationCallbacks;
545 this.originalURI = this.originalURI;
546 this.URI = this.URI;
547 this.owner = channel.owner;
548 this.securityInfo = channel.securityInfo;
549
550 channel = channel.QueryInterface(nsIHttpChannel);
551 if (channel) {
552 this.allowPipelining = channel.allowPipelining;
553 this.redirectionLimit = channel.redirectionLimit;
554 this.referrer = channel.referrer;
555 this.requestMethod = channel.requestMethod;
556 this.requestSucceeded = channel.requestSucceeded;
557 this.responseStatus = channel.responseStatus;
558 this.responseStatusText = channel.responseStatusText;
559 }
560 }
561
562 },
563
564 /* nsIStreamListener */
565 asyncOpenListener: null,
566
567 /* nsISupports (but we really don't care) */
568 asyncOpenContext: null,
569
570
571 /* has the XML finished loading? */
572 loadDone: false,
573
574
575
576/* public fields (nsIStreamListener implementation) */
577 onDataAvailable : function(request, ctx, inputStream, offset, count)
578 {
579 dump("\nonDataAvailable, offset=" + offset + ", count=" + count + "\n");
580
581 // XXX
582/*
583 this.copyFields(request);
584 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, inputStream, offset, count);
585 return;
586*/
587
588
589 if (offset == 0) {
590 this.scriptableInStream.init(inputStream);
591 }
592
593 this.buf += this.scriptableInStream.read(count);
594
595 if (!request.isPending()) {
596 dump("request finished, buf = " + this.buf + "\n");
597
598 this.scriptableInStream = null;
599 }
600 else {
601 dump("request pending...\n");
602 dump("buf so far = " + this.buf + "\n");
603 }
604 },
605
606
607/* public fields (nsIRequestObserver implementation) */
608 onStartRequest : function(request, ctx)
609 {
610 dump("\nonStartRequest called\n");
611 // XXX
612
613 this.copyFields(request);
614 this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext);
615 },
616
617
618 onStopRequest : function(request, ctx, status)
619 {
620 dump("\nonStopRequest called - status " + status + "\n");
621
622 // XXX
623/*
624 this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status);
625 return;
626*/
627
628 this.copyFields(request);
629 this.loadDone = true;
630
631 if (status == 0) {
632
633 var domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
634 var xmlDoc = domParser.parseFromString(this.buf, "text/xml");
635
636 // make fake inputstream
637 var renderedHTML = renderXRDS(xmlDoc);
638
639 this.contentCharset = "UTF-8";
640 this.contentLength = renderedHTML.length;
641 this.contentType = "text/html";
642
643 dump("rendered HTML = \n" + renderedHTML + "\n");
644
645 dump("\nCalling asyncOpenListener.onStartRequest\n\n");
646
647
648 var strIStream = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance(Components.interfaces.nsIStringInputStream);
649 if (strIStream) {
650 strIStream.setData(renderedHTML, renderedHTML.length);
651/*
652 strIStream.setData(this.buf, this.buf.length);
653*/
654 dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n");
655 dump("\nCalling asyncOpenListener.onDataAvailable\n\n");
656 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, renderedHTML.length);
657/*
658 this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, this.buf.length);
659*/
660
661 dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n");
662 }
663 }
664 else {
665 dump("\nStatus = " + status + "\n");
666 dump("Calling asyncOpenListener.onStartRequest\n\n");
667 this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext);
668 }
669
670 dump("stopping request for underlying asyncOpenListener\n");
671
672 this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status);
673
674 // copied from nsIWyciwygChannel
675 this.asyncOpenListener = null;
676 this.asyncOpenContext = null;
677
678/*
679 if (this.loadGroup) {
680 this.loadGroup.removeRequest(request, null, status);
681 }
682*/
683
684 this.notificationCallbacks = null;
685 this.mChannel = null;
686
687 dump("stopped request\n");
688 },
689
690
691/* public fields (nsIInputStream implementation) */
692 available: function()
693 {
694 dump("nsIInputStream::available called\n");
695 return renderedHTML.length;
696 },
697
698 close: function()
699 {
700 dump("nsIInputStream::close called\n");
701 },
702
703 isNonBlocking: function() {
704 dump("nsIInputStream::isNonBlocking called\n");
705 return true;
706 },
707
708 read: function() { dump("nsIInputStream::read() called!!!\n"); },
709
710
711
712
713
714/* public fields (nsIRequest implmentation) */
715
716 loadFlags: 0,
717
718 loadGroup: null,
719
720 name: "xri://request",
721
722 status: 0,
723
724 cancel: function(status) { dump("\ncancel called...\n"); },
725
726 isPending: function() {
727 dump("isPending called\n\n");
728 return !this.loadDone;
729 },
730
731 resume: function() { dump("resume called\n"); },
732
733 suspend: function() { dump("suspend called\n"); },
734
735
736
737/* public fields (nsIChannel implmentation) */
738
739 contentCharset: null,
740
741 contentLength: -1,
742
743 contentType: null,
744
745 notificationCallbacks: null,
746
747 originalURI: null,
748
749 owner: null,
750
751 securityInfo: null,
752
753 URI: null,
754
755 open: function()
756 {
757 dump("open not supporteD!!!!!!\n");
758 },
759
760 asyncOpen: function(listener, context)
761 {
762 dump("asyncOpen called!!!!!!\n");
763 this.asyncOpenListener = listener;
764 this.asyncOpenContext = context;
765
766 var hxri = PROXY_URI + this.qxri
767 + "?_xrd_r=application/xrds%2Bxml;sep=false";
768 var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService();
769 ioService = ioService.QueryInterface(nsIIOService);
770 var channel = ioService.newChannel(hxri, null, null);
771
772 if (this.scriptableInStream) {
773 dump("Hey! You can't possibly be reusing this handler?!\n");
774 return;
775 }
776
777 dump("making scriptableInStream\n");
778 this.scriptableInStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
779 .createInstance(Components.interfaces.nsIScriptableInputStream);
780
781 this.buf = '';
782
783 dump("notificationCallbacks = " + this.notificationCallbacks + "\n");
784 dump("loadFlags = " + this.loadFlags + "\n");
785 dump("loadGroup = " + this.loadGroup + "\n");
786 dump("owner = " + this.owner + "\n");
787 dump("securityInfo = " + this.securityInfo + "\n");
788
789 // these nsIRequest attributes must be copied to the stub
790 // channel that we created
791 channel.notificationCallbacks = this.notificationCallbacks;
792 channel.loadGroup = this.loadGroup;
793 channel.loadFlags = this.loadFlags;
794
795 this.mChannel = channel;
796 channel.asyncOpen(this, null);
797 },
798
799
800/* public fields (nsIChannel implmentation) */
801 allowPipelining: false,
802 redirectionLimit: 5,
803 referrer: "",
804 requestMethod: "GET",
805 requestSucceeded: true,
806 responseStatus: 200,
807 responseStatusText: "OK",
808 getRequestHeader: function(header) {
809 dump("getRequestHeader(" + header + ")\n");
810 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
811
812 try {
813 var val = httpChannel.getRequestHeader(header);
814 dump("getRequestHeader(" + header + ") = " + val + "\n");
815 return val;
816 }
817 catch (e) {
818 throw e;
819 }
820 },
821 getResponseHeader: function(header) {
822 dump("getResponseHeader(" + header + ")\n");
823 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
824
825 try {
826 var val = httpChannel.getResponseHeader(header);
827 dump("getResponseHeader(" + header + ") = " + val + "\n");
828 return val;
829 }
830 catch (e) {
831 throw e;
832 }
833/* XXX
834 if (header == "Content-Type")
835 return "text/html";
836*/
837 return null;
838 },
839 isNoCacheResponse: function() {
840 dump("isNoCacheResponse()\n");
841 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
842 return httpChannel.isNoCacheResponse();
843 },
844 isNoStoreResponse: function() {
845 dump("isNoStoreResponse()\n");
846 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
847 return httpChannel.isNoStoreResponse();
848 return true;
849 },
850 setRequestHeader: function(header, value, merge) {
851 dump("setRequestHeader(" + header + ", " + value + ")\n");
852 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
853 return httpChannel.setRequestHeader(header, value, merge);
854 },
855 setResponseHeader: function(header, value, merge) {
856 dump("setResponseHeader(" + header + ", " + value + ")\n");
857 var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
858 return httpChannel.setResponseHeader(header, value, merge);
859 },
860 visitRequestHeaders: function(visitor) {
861 dump("visitRequestHeaders()\n");
862 },
863 visitResponseHeaders: function(visitor) {
864 dump("visitResponseHeaders()\n");
865 },
866
867 QueryInterface: function(iid)
868 {
869 dump("QI.. \n");
870 if (iid.equals(nsIChannel))
871 dump("QI(nsIChannel)\n");
872 else if (iid.equals(nsIHttpChannel))
873 dump("QI(nsIHttpChannel)\n");
874 else if (iid.equals(Components.interfaces.nsIUploadChannel))
875 dump("QI(nsIUploadChannel) - not supported\n");
876 else if (iid.equals(Components.interfaces.nsICachingChannel))
877 dump("QI(nsICachingChannel) - not supported\n");
878 else if (iid.equals(Components.interfaces.nsIClassInfo))
879 dump("QI(nsIClassInfo) - not supported\n");
880 else if (iid.equals(Components.interfaces.nsISecurityCheckedComponent))
881 dump("QI(nsISecurityCheckedComponent) - not supported\n");
882 else if (iid.equals(Components.interfaces.nsIWyciwygChannel))
883 dump("QI(nsIWyciwygChannel) - not supported\n");
884 else if (iid.equals(Components.interfaces.nsIMultiPartChannel))
885 dump("QI(nsIMultiPartChannel) - not supported\n");
886 else if (iid.equals(Components.interfaces.nsIHttpChannelInternal))
887 dump("QI(nsIHttpChannelInternal) - not supported\n");
888 else if (iid.equals(Components.interfaces.nsIWritablePropertyBag2))
889 dump("QI(nsIWritablePropertyBag2) - not supported\n");
890 else if (iid.equals(nsIRequest))
891 dump("QI(nsIRequest)\n");
892 else if (iid.equals(nsIRequestObserver))
893 dump("QI(nsIRequestObserver)\n");
894 else if (iid.equals(nsISupports))
895 dump("QI(nsISupports)\n");
896 else if (iid.equals(nsIStreamListener))
897 dump("QI(nsIStreamListener)\n");
898 else
899 dump("unknown " + iid + "\n");
900
901 if (iid.equals(nsISupports) ||
902 iid.equals(nsIRequest) ||
903 iid.equals(nsIRequestObserver) ||
904 iid.equals(nsIChannel) ||
905 iid.equals(nsIHttpChannel) ||
906 iid.equals(nsIStreamListener)
907 ) {
908 return this;
909 }
910
911 throw Components.results.NS_ERROR_NO_INTERFACE;
912 }
913};
914
915
916
917/***********************************************************
918 XriProtocolHandler class definition
919 ***********************************************************/
920
921//class constructor
922function XriProtocolHandler() {
923};
924
925// class definition
926XriProtocolHandler.prototype = {
927 defaultPort: 80, // HTTP
928
929 protocolFlags : nsIProtocolHandler.ALLOWS_PROXY | nsIProtocolHandler.ALLOWS_PROXY_HTTP,
930
931 scheme: "xri",
932
933 allowPort: function() {
934 return false; // only called for blacklisted ports, should respect
935 },
936
937 _newHttpChannel: function(aURI)
938 {
939 var HXRI = PROXY_URI + aURI.spec;
940 var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService();
941 ioService = ioService.QueryInterface(nsIIOService);
942 var channel = ioService.newChannel(HXRI, null, null);
943 return channel;
944 },
945
946 newChannel: function(aURI)
947 {
948 // leave alone if path is not empty or just a single slash or query exists
949
950 dump("path='" + aURI.path + "'\n");
951 dump("query='" + aURI.query + "'\n");
952 dump("spec='" + aURI.spec + "'\n");
953
954 var slashPos = aURI.spec.indexOf('/', 'xri://'.length);
955 var qmarkPos = aURI.spec.indexOf('?');
956 dump("slashPos='" + slashPos + "'\n");
957 dump("qmarkPos='" + qmarkPos + "'\n");
958 if ((slashPos > 0 && slashPos < aURI.spec.length - 1) || qmarkPos > -1) {
959 return this._newHttpChannel(aURI);
960 }
961
962 var explorer = new XRIChannel(aURI);
963 return explorer;
964 },
965
966
967 newURI: function(spec, originCharset, baseURI)
968 {
969 var newSpec = spec;
970 if (baseURI != null) {
971 // standard-url (nsIURL) does not work with @-GCS
972 var baseURL = Components.classes[CID_URL].createInstance(nsIURL);
973 baseURL.spec = baseURI.spec;
974 newSpec = baseURL.resolve(spec);
975 }
976
977 var uri = Components.classes[CID_URI].createInstance(nsIURI);
978 uri.spec = newSpec;
979 return uri;
980 },
981
982 QueryInterface: function(aIID)
983 {
984 if (!aIID.equals(nsIProtocolHandler) &&
985 !aIID.equals(nsISupports))
986 throw Components.results.NS_ERROR_NO_INTERFACE;
987 return this;
988 }
989};
990
991
992/***********************************************************
993 class factory
994
995 This object is a member of the global-scope Components.classes.
996 It is keyed off of the contract ID. Eg:
997
998 myXriProtocolHandler = Components.classes["@dietrich.ganx4.com/helloworld;1"].
999 createInstance(Components.interfaces.nsIXriProtocolHandler);
1000
1001 ***********************************************************/
1002var XriProtocolHandlerFactory = {
1003 createInstance: function (aOuter, aIID)
1004 {
1005 if (aOuter != null)
1006 throw Components.results.NS_ERROR_NO_AGGREGATION;
1007 return (new XriProtocolHandler()).QueryInterface(aIID);
1008 }
1009};
1010
1011
1012/***********************************************************
1013 module definition (xpcom registration)
1014 ***********************************************************/
1015var XriProtocolHandlerModule = {
1016
1017 _firstTime: true,
1018
1019 registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
1020 {
1021 if (this._firstTime) {
1022 this._firstTime = false;
1023 throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
1024 }
1025 aCompMgr = aCompMgr.
1026 QueryInterface(Components.interfaces.nsIComponentRegistrar);
1027 aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME,
1028 CONTRACT_ID, aFileSpec, aLocation, aType);
1029 },
1030
1031 unregisterSelf: function(aCompMgr, aLocation, aType)
1032 {
1033 aCompMgr = aCompMgr.
1034 QueryInterface(Components.interfaces.nsIComponentRegistrar);
1035 aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
1036 },
1037
1038 getClassObject: function(aCompMgr, aCID, aIID)
1039 {
1040 if (!aIID.equals(Components.interfaces.nsIFactory))
1041 throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
1042
1043 if (aCID.equals(CLASS_ID))
1044 return XriProtocolHandlerFactory;
1045
1046 throw Components.results.NS_ERROR_NO_INTERFACE;
1047 },
1048
1049 canUnload: function(aCompMgr) { return true; }
1050};
1051
1052
1053/***********************************************************
1054 module initialization
1055
1056 When the application registers the component, this function
1057 is called.
1058 ***********************************************************/
1059function NSGetModule(aCompMgr, aFileSpec) { return XriProtocolHandlerModule; }
1060