summaryrefslogtreecommitdiffstats
path: root/browser/components/feeds/FeedConverter.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/feeds/FeedConverter.js')
-rw-r--r--browser/components/feeds/FeedConverter.js568
1 files changed, 0 insertions, 568 deletions
diff --git a/browser/components/feeds/FeedConverter.js b/browser/components/feeds/FeedConverter.js
deleted file mode 100644
index c2c565608..000000000
--- a/browser/components/feeds/FeedConverter.js
+++ /dev/null
@@ -1,568 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-Components.utils.import("resource://gre/modules/debug.js");
-Components.utils.import("resource://gre/modules/Services.jsm");
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-
-function LOG(str) {
- dump("*** " + str + "\n");
-}
-
-const FS_CONTRACTID = "@mozilla.org/browser/feeds/result-service;1";
-const FPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=feed";
-const PCPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=pcast";
-
-const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
-const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
-const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
-const TYPE_ANY = "*/*";
-
-const PREF_SELECTED_APP = "browser.feeds.handlers.application";
-const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
-const PREF_SELECTED_ACTION = "browser.feeds.handler";
-const PREF_SELECTED_READER = "browser.feeds.handler.default";
-
-const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
-const PREF_VIDEO_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
-const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
-const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
-
-const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
-const PREF_AUDIO_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
-const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
-const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
-
-function getPrefAppForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_APP;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_APP;
-
- default:
- return PREF_SELECTED_APP;
- }
-}
-
-function getPrefWebForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_WEB;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_WEB;
-
- default:
- return PREF_SELECTED_WEB;
- }
-}
-
-function getPrefActionForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_ACTION;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_ACTION;
-
- default:
- return PREF_SELECTED_ACTION;
- }
-}
-
-function getPrefReaderForType(t) {
- switch (t) {
- case Ci.nsIFeed.TYPE_VIDEO:
- return PREF_VIDEO_SELECTED_READER;
-
- case Ci.nsIFeed.TYPE_AUDIO:
- return PREF_AUDIO_SELECTED_READER;
-
- default:
- return PREF_SELECTED_READER;
- }
-}
-
-function safeGetCharPref(pref, defaultValue) {
- var prefs =
- Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch);
- try {
- return prefs.getCharPref(pref);
- }
- catch (e) {
- }
- return defaultValue;
-}
-
-function FeedConverter() {
-}
-FeedConverter.prototype = {
- classID: Components.ID("{229fa115-9412-4d32-baf3-2fc407f76fb1}"),
-
- /**
- * This is the downloaded text data for the feed.
- */
- _data: null,
-
- /**
- * This is the object listening to the conversion, which is ultimately the
- * docshell for the load.
- */
- _listener: null,
-
- /**
- * Records if the feed was sniffed
- */
- _sniffed: false,
-
- /**
- * See nsIStreamConverter.idl
- */
- convert(sourceStream, sourceType, destinationType,
- context) {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- /**
- * See nsIStreamConverter.idl
- */
- asyncConvertData(sourceType, destinationType,
- listener, context) {
- this._listener = listener;
- },
-
- /**
- * Whether or not the preview page is being forced.
- */
- _forcePreviewPage: false,
-
- /**
- * Release our references to various things once we're done using them.
- */
- _releaseHandles() {
- this._listener = null;
- this._request = null;
- this._processor = null;
- },
-
- /**
- * See nsIFeedResultListener.idl
- */
- handleResult(result) {
- // Feeds come in various content types, which our feed sniffer coerces to
- // the maybe.feed type. However, feeds are used as a transport for
- // different data types, e.g. news/blogs (traditional feed), video/audio
- // (podcasts) and photos (photocasts, photostreams). Each of these is
- // different in that there's a different class of application suitable for
- // handling feeds of that type, but without a content-type differentiation
- // it is difficult for us to disambiguate.
- //
- // The other problem is that if the user specifies an auto-action handler
- // for one feed application, the fact that the content type is shared means
- // that all other applications will auto-load with that handler too,
- // regardless of the content-type.
- //
- // This means that content-type alone is not enough to determine whether
- // or not a feed should be auto-handled. This means that for feeds we need
- // to always use this stream converter, even when an auto-action is
- // specified, not the basic one provided by WebContentConverter. This
- // converter needs to consume all of the data and parse it, and based on
- // that determination make a judgment about type.
- //
- // Since there are no content types for this content, and I'm not going to
- // invent any, the upshot is that while a user can set an auto-handler for
- // generic feed content, the system will prevent them from setting an auto-
- // handler for other stream types. In those cases, the user will always see
- // the preview page and have to select a handler. We can guess and show
- // a client handler, but will not be able to show web handlers for those
- // types.
- //
- // If this is just a feed, not some kind of specialized application, then
- // auto-handlers can be set and we should obey them.
- try {
- let feedService =
- Cc["@mozilla.org/browser/feeds/result-service;1"].
- getService(Ci.nsIFeedResultService);
- if (!this._forcePreviewPage && result.doc) {
- let feed = result.doc.QueryInterface(Ci.nsIFeed);
- let handler = safeGetCharPref(getPrefActionForType(feed.type), "ask");
-
- if (handler != "ask") {
- if (handler == "reader")
- handler = safeGetCharPref(getPrefReaderForType(feed.type), "bookmarks");
- switch (handler) {
- case "web":
- let wccr =
- Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
- getService(Ci.nsIWebContentConverterService);
- if ((feed.type == Ci.nsIFeed.TYPE_FEED &&
- wccr.getAutoHandler(TYPE_MAYBE_FEED)) ||
- (feed.type == Ci.nsIFeed.TYPE_VIDEO &&
- wccr.getAutoHandler(TYPE_MAYBE_VIDEO_FEED)) ||
- (feed.type == Ci.nsIFeed.TYPE_AUDIO &&
- wccr.getAutoHandler(TYPE_MAYBE_AUDIO_FEED))) {
- wccr.loadPreferredHandler(this._request);
- return;
- }
- break;
-
- default:
- LOG("unexpected handler: " + handler);
- // fall through -- let feed service handle error
- case "bookmarks":
- case "client":
- case "default":
- try {
- let title = feed.title ? feed.title.plainText() : "";
- let desc = feed.subtitle ? feed.subtitle.plainText() : "";
- feedService.addToClientReader(result.uri.spec, title, desc, feed.type, handler);
- return;
- } catch (ex) { /* fallback to preview mode */ }
- }
- }
- }
-
- let ios =
- Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- let chromeChannel;
-
- // handling a redirect, hence forwarding the loadInfo from the old channel
- // to the newchannel.
- let oldChannel = this._request.QueryInterface(Ci.nsIChannel);
- let loadInfo = oldChannel.loadInfo;
-
- // If there was no automatic handler, or this was a podcast,
- // photostream or some other kind of application, show the preview page
- // if the parser returned a document.
- if (result.doc) {
-
- // Store the result in the result service so that the display
- // page can access it.
- feedService.addFeedResult(result);
-
- // Now load the actual XUL document.
- let aboutFeedsURI = ios.newURI("about:feeds", null, null);
- chromeChannel = ios.newChannelFromURIWithLoadInfo(aboutFeedsURI, loadInfo);
- chromeChannel.originalURI = result.uri;
-
- // carry the origin attributes from the channel that loaded the feed.
- chromeChannel.owner =
- Services.scriptSecurityManager.createCodebasePrincipal(aboutFeedsURI,
- loadInfo.originAttributes);
- } else {
- chromeChannel = ios.newChannelFromURIWithLoadInfo(result.uri, loadInfo);
- }
-
- chromeChannel.loadGroup = this._request.loadGroup;
- chromeChannel.asyncOpen2(this._listener);
- }
- finally {
- this._releaseHandles();
- }
- },
-
- /**
- * See nsIStreamListener.idl
- */
- onDataAvailable(request, context, inputStream,
- sourceOffset, count) {
- if (this._processor)
- this._processor.onDataAvailable(request, context, inputStream,
- sourceOffset, count);
- },
-
- /**
- * See nsIRequestObserver.idl
- */
- onStartRequest(request, context) {
- let channel = request.QueryInterface(Ci.nsIChannel);
-
- // Check for a header that tells us there was no sniffing
- // The value doesn't matter.
- try {
- let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
- // Make sure to check requestSucceeded before the potentially-throwing
- // getResponseHeader.
- if (!httpChannel.requestSucceeded) {
- // Just give up, but don't forget to cancel the channel first!
- request.cancel(Cr.NS_BINDING_ABORTED);
- return;
- }
-
- // Note: this throws if the header is not set.
- httpChannel.getResponseHeader("X-Moz-Is-Feed");
- }
- catch (ex) {
- this._sniffed = true;
- }
-
- this._request = request;
-
- // Save and reset the forced state bit early, in case there's some kind of
- // error.
- let feedService =
- Cc["@mozilla.org/browser/feeds/result-service;1"].
- getService(Ci.nsIFeedResultService);
- this._forcePreviewPage = feedService.forcePreviewPage;
- feedService.forcePreviewPage = false;
-
- // Parse feed data as it comes in
- this._processor =
- Cc["@mozilla.org/feed-processor;1"].
- createInstance(Ci.nsIFeedProcessor);
- this._processor.listener = this;
- this._processor.parseAsync(null, channel.URI);
-
- this._processor.onStartRequest(request, context);
- },
-
- /**
- * See nsIRequestObserver.idl
- */
- onStopRequest(request, context, status) {
- if (this._processor)
- this._processor.onStopRequest(request, context, status);
- },
-
- /**
- * See nsISupports.idl
- */
- QueryInterface(iid) {
- if (iid.equals(Ci.nsIFeedResultListener) ||
- iid.equals(Ci.nsIStreamConverter) ||
- iid.equals(Ci.nsIStreamListener) ||
- iid.equals(Ci.nsIRequestObserver)||
- iid.equals(Ci.nsISupports))
- return this;
- throw Cr.NS_ERROR_NO_INTERFACE;
- },
-};
-
-/**
- * Keeps parsed FeedResults around for use elsewhere in the UI after the stream
- * converter completes.
- */
-function FeedResultService() {
-}
-
-FeedResultService.prototype = {
- classID: Components.ID("{2376201c-bbc6-472f-9b62-7548040a61c6}"),
-
- /**
- * A URI spec -> [nsIFeedResult] hash. We have to keep a list as the
- * value in case the same URI is requested concurrently.
- */
- _results: { },
-
- /**
- * See nsIFeedResultService.idl
- */
- forcePreviewPage: false,
-
- /**
- * See nsIFeedResultService.idl
- */
- addToClientReader(spec, title, subtitle, feedType, feedReader) {
- if (!feedReader) {
- feedReader = "default";
- }
-
- let handler = safeGetCharPref(getPrefActionForType(feedType), "bookmarks");
- if (handler == "ask" || handler == "reader")
- handler = feedReader;
-
- switch (handler) {
- case "client":
- Services.cpmm.sendAsyncMessage("FeedConverter:ExecuteClientApp",
- { spec,
- title,
- subtitle,
- feedHandler: getPrefAppForType(feedType) });
- break;
- case "default":
- // Default system feed reader
- Services.cpmm.sendAsyncMessage("FeedConverter:ExecuteClientApp",
- { spec,
- title,
- subtitle,
- feedHandler: "default" });
- break;
- default:
- // "web" should have been handled elsewhere
- LOG("unexpected handler: " + handler);
- // fall through
- case "bookmarks":
- Services.cpmm.sendAsyncMessage("FeedConverter:addLiveBookmark",
- { spec, title, subtitle });
- break;
- }
- },
-
- /**
- * See nsIFeedResultService.idl
- */
- addFeedResult(feedResult) {
- NS_ASSERT(feedResult.uri != null, "null URI!");
- NS_ASSERT(feedResult.uri != null, "null feedResult!");
- let spec = feedResult.uri.spec;
- if (!this._results[spec])
- this._results[spec] = [];
- this._results[spec].push(feedResult);
- },
-
- /**
- * See nsIFeedResultService.idl
- */
- getFeedResult(uri) {
- NS_ASSERT(uri != null, "null URI!");
- let resultList = this._results[uri.spec];
- for (let result of resultList) {
- if (result.uri == uri)
- return result;
- }
- return null;
- },
-
- /**
- * See nsIFeedResultService.idl
- */
- removeFeedResult(uri) {
- NS_ASSERT(uri != null, "null URI!");
- let resultList = this._results[uri.spec];
- if (!resultList)
- return;
- let deletions = 0;
- for (let i = 0; i < resultList.length; ++i) {
- if (resultList[i].uri == uri) {
- delete resultList[i];
- ++deletions;
- }
- }
-
- // send the holes to the end
- resultList.sort();
- // and trim the list
- resultList.splice(resultList.length - deletions, deletions);
- if (resultList.length == 0)
- delete this._results[uri.spec];
- },
-
- createInstance(outer, iid) {
- if (outer != null)
- throw Cr.NS_ERROR_NO_AGGREGATION;
- return this.QueryInterface(iid);
- },
-
- QueryInterface(iid) {
- if (iid.equals(Ci.nsIFeedResultService) ||
- iid.equals(Ci.nsIFactory) ||
- iid.equals(Ci.nsISupports))
- return this;
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-};
-
-/**
- * A protocol handler that attempts to deal with the variant forms of feed:
- * URIs that are actually either http or https.
- */
-function GenericProtocolHandler() {
-}
-GenericProtocolHandler.prototype = {
- _init(scheme) {
- let ios =
- Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
- this._http = ios.getProtocolHandler("http");
- this._scheme = scheme;
- },
-
- get scheme() {
- return this._scheme;
- },
-
- get protocolFlags() {
- let {URI_DANGEROUS_TO_LOAD, ALLOWS_PROXY_HTTP, ALLOWS_PROXY} =
- Ci.nsIProtocolHandler;
- return URI_DANGEROUS_TO_LOAD | ALLOWS_PROXY | ALLOWS_PROXY_HTTP;
- },
-
- get defaultPort() {
- return this._http.defaultPort;
- },
-
- allowPort(port, scheme) {
- return this._http.allowPort(port, scheme);
- },
-
- newURI(spec, originalCharset, baseURI) {
- // Feed URIs can be either nested URIs of the form feed:realURI (in which
- // case we create a nested URI for the realURI) or feed://example.com, in
- // which case we create a nested URI for the real protocol which is http.
-
- let scheme = this._scheme + ":";
- if (spec.substr(0, scheme.length) != scheme)
- throw Cr.NS_ERROR_MALFORMED_URI;
-
- let prefix = spec.substr(scheme.length, 2) == "//" ? "http:" : "";
- let inner = Services.io.newURI(spec.replace(scheme, prefix),
- originalCharset, baseURI);
-
- if (!["http", "https"].includes(inner.scheme))
- throw Cr.NS_ERROR_MALFORMED_URI;
-
- let uri = Services.io.QueryInterface(Ci.nsINetUtil).newSimpleNestedURI(inner);
- uri.spec = inner.spec.replace(prefix, scheme);
- return uri;
- },
-
- newChannel2(aUri, aLoadInfo) {
- let inner = aUri.QueryInterface(Ci.nsINestedURI).innerURI;
- let channel = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService).
- newChannelFromURIWithLoadInfo(inner, aLoadInfo);
-
- if (channel instanceof Components.interfaces.nsIHttpChannel)
- // Set this so we know this is supposed to be a feed
- channel.setRequestHeader("X-Moz-Is-Feed", "1", false);
- channel.originalURI = aUri;
- return channel;
- },
-
- QueryInterface(iid) {
- if (iid.equals(Ci.nsIProtocolHandler) ||
- iid.equals(Ci.nsISupports))
- return this;
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
-};
-
-function FeedProtocolHandler() {
- this._init('feed');
-}
-FeedProtocolHandler.prototype = new GenericProtocolHandler();
-FeedProtocolHandler.prototype.classID = Components.ID("{4f91ef2e-57ba-472e-ab7a-b4999e42d6c0}");
-
-function PodCastProtocolHandler() {
- this._init('pcast');
-}
-PodCastProtocolHandler.prototype = new GenericProtocolHandler();
-PodCastProtocolHandler.prototype.classID = Components.ID("{1c31ed79-accd-4b94-b517-06e0c81999d5}");
-
-var components = [FeedConverter,
- FeedResultService,
- FeedProtocolHandler,
- PodCastProtocolHandler];
-
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);