author | Michael Krelin <hacker@klever.net> | 2008-03-01 17:26:13 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2008-03-01 17:26:13 (UTC) |
commit | b2e587331d0020fa2bf35e5a5ada249020858e14 (patch) (side-by-side diff) | |
tree | 1b6b490275bb54b6f579bad3cf6592a1677aa0a8 | |
parent | fe00dd0be8fd88dc8179eed7a38663f07c1288a7 (diff) | |
download | foxri-b2e587331d0020fa2bf35e5a5ada249020858e14.zip foxri-b2e587331d0020fa2bf35e5a5ada249020858e14.tar.gz foxri-b2e587331d0020fa2bf35e5a5ada249020858e14.tar.bz2 |
Signed-off-by: Michael Krelin <hacker@klever.net>
-rwxr-xr-x | src/components/xriProtocolHandler.js | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/src/components/xriProtocolHandler.js b/src/components/xriProtocolHandler.js index 3d27784..2e09f64 100755 --- a/src/components/xriProtocolHandler.js +++ b/src/components/xriProtocolHandler.js @@ -1,1063 +1,1065 @@ /***********************************************************
constants
***********************************************************/
// The interface we implement - nsIProtocolHandler
const nsIProtocolHandler = Components.interfaces.nsIProtocolHandler;
// Interfaces that we require
const nsISupports = Components.interfaces.nsISupports;
const nsIIOService = Components.interfaces.nsIIOService;
const nsIURI = Components.interfaces.nsIURI;
const nsIURL = Components.interfaces.nsIURL;
const nsIRequest = Components.interfaces.nsIRequest;
const nsIRequestObserver = Components.interfaces.nsIRequestObserver;
const nsIChannel = Components.interfaces.nsIChannel;
const nsIHttpChannel = Components.interfaces.nsIHttpChannel;
const nsIStreamListener = Components.interfaces.nsIStreamListener;
// UUID uniquely identifying our component
// You can get from: http://kruithof.xs4all.nl/uuid/uuidgen here
const CLASS_ID = Components.ID("{ea00b610-215a-11db-a98b-0800200c9a66}");
// textual unique identifier
const CONTRACT_ID = "@mozilla.org/network/protocol;1?name=xri";
// Components that we require
const CID_URI = "@mozilla.org/network/simple-uri;1";
const kIOSERVICE_CID_STR = "{9ac9e770-18bc-11d3-9337-00104ba0fd40}";
const CID_URL = "@mozilla.org/network/standard-url;1";
// description
const CLASS_NAME = "XRI Protocol Handler";
const PROXY_URI = "http://xri.net/";
const XP_ANY_TYPE = 0;
const XP_NUMBER_TYPE = 1;
const XP_STRING_TYPE = 2;
const XP_BOOLEAN_TYPE = 3;
const XP_UNORDERED_NODE_ITERATOR_TYPE = 4;
const XP_ORDERED_NODE_ITERATOR_TYPE = 5;
const XP_UNORDERED_NODE_SNAPSHOT_TYPE = 6;
const XP_ORDERED_NODE_SNAPSHOT_TYPE = 7;
const XP_ANY_UNORDERED_NODE_TYPE = 8;
const XP_FIRST_ORDERED_NODE_TYPE = 9;
var SERVICE_CLASSES = {
'xri://+i-service*(+contact)*($v*1.0)': 'i-contact',
'http://openid.net/signon/1.0': 'openid',
'http://openid.net/signon/1.1': 'openid',
'http://specs.openid.net/auth/2.0/signon': 'openid',
'http://specs.openid.net/auth/2.0/server': 'openid',
'xri://$res*auth*($v*2.0)': 'res-auth',
'xri://+i-service*(+authn)*(+saml)*($v*1.0)': 'authn-saml',
'xri://+i-service*(+metadata)*(+saml)*($v*1.0)' : 'metadata-saml',
'xri://+i-service*(+forwarding)*($v*1.0)': 'i-forwarding'
};
const HTML_HEAD = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\
<head>\n\
<title>FoXRI Explorer - #QXRI#</title>\n\
<link href=\"chrome://foxri/content/foxri_explorer.css\" rel=\"stylesheet\" type=\"text/css\" />\n\
<body>\n\
<h1>FoXRI Explorer</h1>\n\
<div id=\"explorer_body\">\n";
const HTML_FOOT = "</div>\n\
</body>\n\
</html>";
/// Generic object method wrapper
function methodWrapper(obj, method)
{
return (
function() {
/* pass it this inner closure's arguments */
obj[method](arguments);
}
);
}
/// XRDS utility functions
var nsResolver = {
lookupNamespaceURI: function(prefix)
{
if (prefix == "xrds")
return "xri://$xrds";
else if (prefix == "xrd")
return "xri://$xrd*($v*2.0)";
return "";
}
};
function runExpr(doc, context, expr, returnType)
{
if (!returnType)
returnType = XP_ANY_TYPE;
var res = doc.evaluate(expr, context, nsResolver, returnType, null);
return res;
}
function getNumeric(doc, context, expr)
{
var res = runExpr(doc, context, expr, XP_NUMBER_TYPE);
if (res)
return res.numberValue;
return null;
}
function getString(doc, context, expr)
{
// var res = runExpr(doc, context, expr, XPathResult.STRING_TYPE);
var res = runExpr(doc, context, expr, XP_STRING_TYPE);
if (res)
return res.stringValue;
return null;
}
function getNode(doc, context, expr)
{
var res = runExpr(doc, context, expr, XP_FIRST_ORDERED_NODE_TYPE);
if (res)
return res.singleNodeValue;
return null;
}
function getFinalXRD(doc)
{
var lastNode = doc.firstChild;
while (true) {
var node = getNode(doc, lastNode, "xrds:XRDS[position()=last()]");
if (!node)
break;
lastNode = node;
}
return getNode(doc, lastNode, "xrd:XRD[position()=last()]");
}
function isIName(xri)
{
if (xri.match('^xri://.!', 'i')) {
return false;
}
if (xri.match('^.!', 'i')) {
return false;
}
return true;
}
function arraySearch(a, re)
{
var returnArr = new Array();
var i;
for (i = 0; i < a.length; i++) {
if (a[i].match(re)) {
returnArr.push(a[i]);
}
}
return returnArr;
}
function renderService(srv, doc, qxri)
{
var html_types = '';
var html_paths = '';
var html_mediatypes = '';
var html_uris = '';
var html_actions = '';
var serviceName = friendlyServiceName(null);
var serviceType; // the last non-null Type
var knownServiceType; // first recognized service type
// get the types
var res = runExpr(doc, srv, "xrd:Type/text()");
var t;
while (t = res.iterateNext()) {
if (t.nodeValue) {
if (!knownServiceType && isKnownServiceType(t.nodeValue)) {
knownServiceType = t.nodeValue;
}
serviceType = t.nodeValue;
html_types += "<strong>Type:</strong> " + t.nodeValue + "<br/>";
}
}
// get the paths
res = runExpr(doc, srv, "xrd:Path/text()");
var p;
var qxri_prefix = qxri;
if (qxri_prefix.charAt(qxri_prefix.length - 1) != '/') {
qxri_prefix += '/';
}
while (p = res.iterateNext()) {
if (p.nodeValue) {
html_paths += "<strong>Path:</strong> " + p.nodeValue
+ " [ <tt><a href=\"" + qxri_prefix + p.nodeValue + "\">"
+ qxri_prefix + p.nodeValue + "</a></tt> ]"
+ "<br/>\n";
}
}
// get the mediatypes
mediaTypes = new Array();
res = runExpr(doc, srv, "xrd:MediaType/text()");
var m;
while (m = res.iterateNext()) {
if (!knownServiceType) {
var srvType = guessServiceTypeByMime(m.nodeValue);
knownServiceType = srvType? srvType : null;
}
mediaTypes.push(m.nodeValue);
if (m.nodeValue) {
html_mediatypes += "<strong>Media Type:</strong> " + m.nodeValue + "<br/>";
}
}
res = runExpr(doc, srv, "xrd:URI");
var uu;
while (uu = res.iterateNext()) {
var u = uu.firstChild;
if (!(u.nodeValue && u.nodeType==3))
continue;
var srvType = guessServiceTypeByURI(u.nodeValue);
if (!knownServiceType) {
knownServiceType = srvType;
}
html_uris += "<div class=\"" + getServiceClass(srvType) + "\">";
var linkContent = u.nodeValue;
var uriParts = u.nodeValue.match('^(.*):(.*)$');
if (!uriParts)
continue;
if (uriParts[1] == 'data') {
uriParts = uriParts[2].match('^(.*/.*),(.*)');
if (uriParts && uriParts[1].match('^image/', 'i')) {
linkContent = "<img src=\"" + u.nodeValue + "\"/>";
}
else if (uriParts) {
linkContent = uriParts[1] + " data";
}
}
else if (uriParts[1] == 'skype') {
uriParts = uriParts[2].match('^(.*)\\?(.*)');
if (uriParts) {
if (uriParts[2] == "call") {
linkContent = "<img src=\"chrome://foxri/content/skype_call_large.png\" alt=\"Call " + uriParts[1] + "\"/>";
}
else if (uriParts[2] == "chat") {
linkContent = "<img src=\"chrome://foxri/content/skype_chat_large.png\" alt=\"Chat with " + uriParts[1] + "\"/>";
}
else if (uriParts[2] == "add") {
linkContent = "<img src=\"chrome://foxri/content/skype_add_large.png\" alt=\"Add " + uriParts[1] + " to Skype\"/>";
}
}
}
else if (uriParts[1] == 'aim') {
uriParts = uriParts[2].match('^(.*)\\?.*screenname=([^&]*)', 'i');
if (uriParts) {
linkContent = "<img src=\"chrome://foxri/content/aim_logo.gif\" alt=\"Chat with " + uriParts[2] + "\"/> Chat with " + uriParts[2];
}
}
var linkhref = u.nodeValue;
var xrap = uu.getAttribute('append');
if(xrap=='qxri') {
linkhref += qxri.replace(/^xri:\/\//,'');
+ }else if(xrap=='authority') {
+ linkhref += qxri.replace(/^xri:\/\//,'').replace(/\//.*,'');
}else if(xrap!=null){
dump("Unhandled @append: "+xrap+"\n");
}
html_uris += "<a href=\""+linkhref+"\">"
+ linkContent + "</a>";
html_uris += "</div>";
}
var html = "<div class=\"service srv_" + getServiceClass(knownServiceType) + "\">\n";
html += html_types;
html += html_paths;
html += html_mediatypes;
if (html_uris) {
html += "<strong>URI(s):</strong><br/>\n";
html += html_uris;
}
html += "</div>";
return html;
}
function isKnownServiceType(type)
{
if (type.toLowerCase() in SERVICE_CLASSES) {
return true;
}
return false;
}
function getServiceClass(type)
{
if (type && isKnownServiceType(type)) {
return SERVICE_CLASSES[type.toLowerCase()];
}
return type;
}
function guessServiceTypeByURI(uri)
{
if (uri == null || uri == "") {
return "unknown";
}
if (uri.match(/^https?:/i)) {
return "www";
}
else if (uri.match(/^skype:/i)) {
return "skype";
}
else if (uri.match(/^aim:/i)) {
return "aim";
}
else if (uri.match(/^xmpp:/i)) {
return "jabber";
}
else if (uri.match(/^tel:/i)) {
return "tel";
}
else if (uri.match(/^callto:/i)) {
return "callto";
}
else if (uri.match(/^telnet:/i)) {
return "telnet";
}
else if (uri.match(/^news:/i)) {
return "news";
}
else if (uri.match(/^nntp:/i)) {
return "nntp";
}
else if (uri.match(/^ftp:/i)) {
return "ftp";
}
else if (uri.match(/^mailto:/i)) {
return "email";
}
else if (uri.match(/^urn:/i)) {
return "urn";
}
else if (uri.match(/^data:/i)) {
return "data";
}
else if (uri.match(/^feed:/i)) {
return "feed";
}
return "unknown";
}
function guessServiceTypeByMime(mimeType)
{
if (mimeType.match(/^application\/(rss|atom)\+xml/i)) {
dump("feed detected!\n");
return "feed";
}
else if (mimeType.match(/^image\//i)) {
return "image";
}
return null;
}
function friendlyServiceName(srvType, uri)
{
if (srvType && srvType == "xri://+i-service*(+contact)*($v*1.0)") {
return "Contact Service";
}
else if (srvType && (
srvType == "http://openid.net/signon/1.0"
|| srvType == "http://openid.net/signon/1.1"
|| srvType == "http://specs.openid.net/auth/2.0/signon"
|| srcType == "http://specs.openid.net/auth/2.0/server"
) ) {
return "OpenID Authentication Service";
}
else if (srvType && srvType == "xri://$res*auth*($v*2.0)") {
return "Authority Resolution Service";
}
else {
if (uri == null) {
return "Generic Service";
}
if (uri.match(/^https?:/i)) {
return "Web Link";
}
else if (uri.match(/^skype:/i)) {
var user = uri.substring("skype:".length, uri.indexOf('?'));
return "Skype <a href=\"" + uri + "\"><img src=\"chrome://foxri/content/skype_call.png\"></a>";
}
else if (uri.match(/^mailto:/i)) {
var qmark = uri.indexOf('?');
var email = (qmark == -1)?
uri.substr("mailto:".length) :
uri.substring("mailto:".length, qmark);
return "Email (address: " + email + ")";
}
else if (srvType != null) {
return srvType; // return verbatim
}
return "Generic Service";
}
}
function subHTML(template, vars)
{
for (key in vars) {
template = template.replace(key, vars[key], 'g');
}
return template;
}
/// Given the completed XMLHttpRequest object, renders the XRDS
function renderXRDS(xmlDoc)
{
var x = xmlDoc;
var qxri = getString(x, x, "/xrds:XRDS/@ref");
var html = subHTML(HTML_HEAD, { '#QXRI#': qxri });
// TODO: render parents as well
var lastNode = getFinalXRD(x);
if (lastNode) {
var stat = getString(x, lastNode, "xrd:Status/@code");
if (stat == "100") {
html += "<h3>Exploring <strong>" + qxri + "</strong></h3>";
}
else {
var msg = getString(x, lastNode, "xrd:Status/text()");
html += "<h3 class=\"error\"><strong>" + qxri + "</strong> failed to resolve (reason: " + stat + " - " + msg + ")</h3>";
}
html += "<br/>";
var services = runExpr(x, lastNode, "xrd:Service");
var s;
var count = getNumeric(x, lastNode, "count(xrd:Service)");
if (count > 0) {
while (s = services.iterateNext()) {
count++;
html += renderService(s, x, qxri);
}
}
else if (stat == '222') {
var xriType = isIName(qxri)? 'I-name' : 'I-number';
html += "<p class='error'>" + xriType + " does not exist.</p>\n";
}
else {
html += "<p>No service has been configured for this XRI</p>";
}
}
html += "</html>";
return html;
}
/***********************************************************
XriServiceExplorer class definition
***********************************************************/
function XRIChannel(uri) {
this.URI = uri;
var r = uri.spec.indexOf('#');
if (r >= 0) {
this.qxri = uri.spec.substring(0, r);
this.fragment = uri.spec.substring(r);
}
else {
this.qxri = uri.spec;
}
};
XRIChannel.prototype = {
fragment: null,
/* private fields used internally */
qxri: null,
xmlRequest: null,
renderedHTML: null,
scriptableInStream: null,
buf: null,
mChannel: null,
copyFields: function(request)
{
dump("copyFields(loadFlags=" + request.loadFlags + ")\n");
dump("loadGroup = " + request.loadGroup + "\n");
dump("notificationCallbacks = " + request.notificationCallbacks + "\n");
// copy request fields
this.loadFlags = request.loadFlags;
this.loadGroup = request.loadGroup;
this.name = request.name;
this.status = request.status;
var channel = request.QueryInterface(nsIChannel);
if (channel) {
this.contentCharset = channel.contentCharset;
this.contentLength = channel.contentLength;
this.contentType = channel.contentType; // XXX
this.contentType = "text/html";
this.notificationCallbacks = channel.notificationCallbacks;
this.originalURI = this.originalURI;
this.URI = this.URI;
this.owner = channel.owner;
this.securityInfo = channel.securityInfo;
channel = channel.QueryInterface(nsIHttpChannel);
if (channel) {
this.allowPipelining = channel.allowPipelining;
this.redirectionLimit = channel.redirectionLimit;
this.referrer = channel.referrer;
this.requestMethod = channel.requestMethod;
this.requestSucceeded = channel.requestSucceeded;
this.responseStatus = channel.responseStatus;
this.responseStatusText = channel.responseStatusText;
}
}
},
/* nsIStreamListener */
asyncOpenListener: null,
/* nsISupports (but we really don't care) */
asyncOpenContext: null,
/* has the XML finished loading? */
loadDone: false,
/* public fields (nsIStreamListener implementation) */
onDataAvailable : function(request, ctx, inputStream, offset, count)
{
dump("\nonDataAvailable, offset=" + offset + ", count=" + count + "\n");
// XXX
/*
this.copyFields(request);
this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, inputStream, offset, count);
return;
*/
if (offset == 0) {
this.scriptableInStream.init(inputStream);
}
this.buf += this.scriptableInStream.read(count);
if (!request.isPending()) {
dump("request finished, buf = " + this.buf + "\n");
this.scriptableInStream = null;
}
else {
dump("request pending...\n");
dump("buf so far = " + this.buf + "\n");
}
},
/* public fields (nsIRequestObserver implementation) */
onStartRequest : function(request, ctx)
{
dump("\nonStartRequest called\n");
// XXX
this.copyFields(request);
this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext);
},
onStopRequest : function(request, ctx, status)
{
dump("\nonStopRequest called - status " + status + "\n");
// XXX
/*
this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status);
return;
*/
this.copyFields(request);
this.loadDone = true;
if (status == 0) {
var domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser);
var xmlDoc = domParser.parseFromString(this.buf, "text/xml");
// make fake inputstream
var renderedHTML = renderXRDS(xmlDoc);
this.contentCharset = "UTF-8";
this.contentLength = renderedHTML.length;
this.contentType = "text/html";
dump("rendered HTML = \n" + renderedHTML + "\n");
dump("\nCalling asyncOpenListener.onStartRequest\n\n");
var strIStream = Components.classes["@mozilla.org/io/string-input-stream;1"].createInstance(Components.interfaces.nsIStringInputStream);
if (strIStream) {
strIStream.setData(renderedHTML, renderedHTML.length);
/*
strIStream.setData(this.buf, this.buf.length);
*/
dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n");
dump("\nCalling asyncOpenListener.onDataAvailable\n\n");
this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, renderedHTML.length);
/*
this.asyncOpenListener.onDataAvailable(this, this.asyncOpenContext, strIStream, 0, this.buf.length);
*/
dump("\nleftovers in string-input-stream = " + strIStream.available() + "\n");
}
}
else {
dump("\nStatus = " + status + "\n");
dump("Calling asyncOpenListener.onStartRequest\n\n");
this.asyncOpenListener.onStartRequest(this, this.asyncOpenContext);
}
dump("stopping request for underlying asyncOpenListener\n");
this.asyncOpenListener.onStopRequest(this, this.asyncOpenContext, status);
// copied from nsIWyciwygChannel
this.asyncOpenListener = null;
this.asyncOpenContext = null;
/*
if (this.loadGroup) {
this.loadGroup.removeRequest(request, null, status);
}
*/
this.notificationCallbacks = null;
this.mChannel = null;
dump("stopped request\n");
},
/* public fields (nsIInputStream implementation) */
available: function()
{
dump("nsIInputStream::available called\n");
return renderedHTML.length;
},
close: function()
{
dump("nsIInputStream::close called\n");
},
isNonBlocking: function() {
dump("nsIInputStream::isNonBlocking called\n");
return true;
},
read: function() { dump("nsIInputStream::read() called!!!\n"); },
/* public fields (nsIRequest implmentation) */
loadFlags: 0,
loadGroup: null,
name: "xri://request",
status: 0,
cancel: function(status) { dump("\ncancel called...\n"); },
isPending: function() {
dump("isPending called\n\n");
return !this.loadDone;
},
resume: function() { dump("resume called\n"); },
suspend: function() { dump("suspend called\n"); },
/* public fields (nsIChannel implmentation) */
contentCharset: null,
contentLength: -1,
contentType: null,
notificationCallbacks: null,
originalURI: null,
owner: null,
securityInfo: null,
URI: null,
open: function()
{
dump("open not supporteD!!!!!!\n");
},
asyncOpen: function(listener, context)
{
dump("asyncOpen called!!!!!!\n");
this.asyncOpenListener = listener;
this.asyncOpenContext = context;
var hxri = PROXY_URI + this.qxri
+ "?_xrd_r=application/xrds%2Bxml;sep=false";
var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService();
ioService = ioService.QueryInterface(nsIIOService);
var channel = ioService.newChannel(hxri, null, null);
if (this.scriptableInStream) {
dump("Hey! You can't possibly be reusing this handler?!\n");
return;
}
dump("making scriptableInStream\n");
this.scriptableInStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
.createInstance(Components.interfaces.nsIScriptableInputStream);
this.buf = '';
dump("notificationCallbacks = " + this.notificationCallbacks + "\n");
dump("loadFlags = " + this.loadFlags + "\n");
dump("loadGroup = " + this.loadGroup + "\n");
dump("owner = " + this.owner + "\n");
dump("securityInfo = " + this.securityInfo + "\n");
// these nsIRequest attributes must be copied to the stub
// channel that we created
channel.notificationCallbacks = this.notificationCallbacks;
channel.loadGroup = this.loadGroup;
channel.loadFlags = this.loadFlags;
this.mChannel = channel;
channel.asyncOpen(this, null);
},
/* public fields (nsIChannel implementation) */
allowPipelining: false,
redirectionLimit: 5,
referrer: "",
requestMethod: "GET",
requestSucceeded: true,
responseStatus: 200,
responseStatusText: "OK",
getRequestHeader: function(header) {
dump("getRequestHeader(" + header + ")\n");
var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
try {
var val = httpChannel.getRequestHeader(header);
dump("getRequestHeader(" + header + ") = " + val + "\n");
return val;
}
catch (e) {
dump("getRequestHeader - got exception: " + e + "\n");
throw e;
}
},
getResponseHeader: function(header) {
dump("getResponseHeader(" + header + ")\n");
var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
try {
var val = httpChannel.getResponseHeader(header);
dump("getResponseHeader(" + header + ") = " + val + "\n");
return val;
}
catch (e) {
dump("getResponseHeader - got exception: " + e + "\n");
throw e;
}
return null;
},
isNoCacheResponse: function() {
dump("isNoCacheResponse()\n");
var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
return httpChannel.isNoCacheResponse();
},
isNoStoreResponse: function() {
dump("isNoStoreResponse()\n");
var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
return httpChannel.isNoStoreResponse();
return true;
},
setRequestHeader: function(header, value, merge) {
dump("setRequestHeader(" + header + ", " + value + ")\n");
var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
return httpChannel.setRequestHeader(header, value, merge);
},
setResponseHeader: function(header, value, merge) {
dump("setResponseHeader(" + header + ", " + value + ")\n");
var httpChannel = this.mChannel.QueryInterface(nsIHttpChannel);
return httpChannel.setResponseHeader(header, value, merge);
},
visitRequestHeaders: function(visitor) {
dump("visitRequestHeaders()\n");
},
visitResponseHeaders: function(visitor) {
dump("visitResponseHeaders()\n");
},
QueryInterface: function(iid)
{
dump("QI.. \n");
if (iid.equals(nsIChannel))
dump("QI(nsIChannel)\n");
else if (iid.equals(nsIHttpChannel))
dump("QI(nsIHttpChannel)\n");
else if (iid.equals(Components.interfaces.nsIUploadChannel))
dump("QI(nsIUploadChannel) - not supported\n");
else if (iid.equals(Components.interfaces.nsICachingChannel))
dump("QI(nsICachingChannel) - not supported\n");
else if (iid.equals(Components.interfaces.nsIClassInfo))
dump("QI(nsIClassInfo) - not supported\n");
else if (iid.equals(Components.interfaces.nsISecurityCheckedComponent))
dump("QI(nsISecurityCheckedComponent) - not supported\n");
else if (iid.equals(Components.interfaces.nsIWyciwygChannel))
dump("QI(nsIWyciwygChannel) - not supported\n");
else if (iid.equals(Components.interfaces.nsIMultiPartChannel))
dump("QI(nsIMultiPartChannel) - not supported\n");
else if (iid.equals(Components.interfaces.nsIHttpChannelInternal))
dump("QI(nsIHttpChannelInternal) - not supported\n");
else if (iid.equals(Components.interfaces.nsIWritablePropertyBag2))
dump("QI(nsIWritablePropertyBag2) - not supported\n");
else if (iid.equals(nsIRequest))
dump("QI(nsIRequest)\n");
else if (iid.equals(nsIRequestObserver))
dump("QI(nsIRequestObserver)\n");
else if (iid.equals(nsISupports))
dump("QI(nsISupports)\n");
else if (iid.equals(nsIStreamListener))
dump("QI(nsIStreamListener)\n");
else
dump("unknown " + iid + "\n");
if (iid.equals(nsISupports) ||
iid.equals(nsIRequest) ||
iid.equals(nsIRequestObserver) ||
iid.equals(nsIChannel) ||
iid.equals(nsIHttpChannel) ||
iid.equals(nsIStreamListener)
) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
/***********************************************************
XriProtocolHandler class definition
***********************************************************/
//class constructor
function XriProtocolHandler() {
};
// class definition
XriProtocolHandler.prototype = {
defaultPort: 80, // HTTP
protocolFlags : nsIProtocolHandler.ALLOWS_PROXY | nsIProtocolHandler.ALLOWS_PROXY_HTTP,
scheme: "xri",
allowPort: function() {
return false; // only called for blacklisted ports, should respect
},
_newHttpChannel: function(aURI)
{
var HXRI = PROXY_URI + aURI.spec;
var ioService = Components.classesByID[kIOSERVICE_CID_STR].getService();
ioService = ioService.QueryInterface(nsIIOService);
var channel = ioService.newChannel(HXRI, null, null);
return channel;
},
newChannel: function(aURI)
{
// leave alone if path is not empty or just a single slash or query exists
dump("path='" + aURI.path + "'\n");
dump("query='" + aURI.query + "'\n");
dump("spec='" + aURI.spec + "'\n");
var slashPos = aURI.spec.indexOf('/', 'xri://'.length);
var qmarkPos = aURI.spec.indexOf('?');
dump("slashPos='" + slashPos + "'\n");
dump("qmarkPos='" + qmarkPos + "'\n");
if ((slashPos > 0 && slashPos < aURI.spec.length - 1) || qmarkPos > -1) {
return this._newHttpChannel(aURI);
}
var explorer = new XRIChannel(aURI);
return explorer;
},
newURI: function(spec, originCharset, baseURI)
{
var newSpec = spec;
if (baseURI != null) {
// standard-url (nsIURL) does not work with @-GCS
var baseURL = Components.classes[CID_URL].createInstance(nsIURL);
baseURL.spec = baseURI.spec;
newSpec = baseURL.resolve(spec);
}
var uri = Components.classes[CID_URI].createInstance(nsIURI);
uri.spec = newSpec;
return uri;
},
QueryInterface: function(aIID)
{
if (!aIID.equals(nsIProtocolHandler) &&
!aIID.equals(nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
/***********************************************************
class factory
This object is a member of the global-scope Components.classes.
It is keyed off of the contract ID. Eg:
myXriProtocolHandler = Components.classes["@dietrich.ganx4.com/helloworld;1"].
createInstance(Components.interfaces.nsIXriProtocolHandler);
***********************************************************/
var XriProtocolHandlerFactory = {
createInstance: function (aOuter, aIID)
{
if (aOuter != null)
throw Components.results.NS_ERROR_NO_AGGREGATION;
return (new XriProtocolHandler()).QueryInterface(aIID);
}
};
/***********************************************************
module definition (xpcom registration)
***********************************************************/
var XriProtocolHandlerModule = {
_firstTime: true,
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
{
if (this._firstTime) {
this._firstTime = false;
throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
}
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME,
CONTRACT_ID, aFileSpec, aLocation, aType);
},
unregisterSelf: function(aCompMgr, aLocation, aType)
{
aCompMgr = aCompMgr.
QueryInterface(Components.interfaces.nsIComponentRegistrar);
aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);
},
getClassObject: function(aCompMgr, aCID, aIID)
{
if (!aIID.equals(Components.interfaces.nsIFactory))
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(CLASS_ID))
return XriProtocolHandlerFactory;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
canUnload: function(aCompMgr) { return true; }
|