1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/* 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/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
function makeDefaultFaviconChannel(uri, loadInfo) {
let channel = Services.io.newChannelFromURIWithLoadInfo(
PlacesUtils.favicons.defaultFavicon, loadInfo);
channel.originalURI = uri;
return channel;
}
function streamDefaultFavicon(uri, loadInfo, outputStream) {
try {
// Open up a new channel to get that data, and push it to our output stream.
// Create a listener to hand data to the pipe's output stream.
let listener = Cc["@mozilla.org/network/simple-stream-listener;1"]
.createInstance(Ci.nsISimpleStreamListener);
listener.init(outputStream, {
onStartRequest(request, context) {},
onStopRequest(request, context, statusCode) {
// We must close the outputStream regardless.
outputStream.close();
}
});
let defaultIconChannel = makeDefaultFaviconChannel(uri, loadInfo);
defaultIconChannel.asyncOpen2(listener);
} catch (ex) {
Cu.reportError(ex);
outputStream.close();
}
}
function PageIconProtocolHandler() {
}
PageIconProtocolHandler.prototype = {
get scheme() {
return "page-icon";
},
get defaultPort() {
return -1;
},
get protocolFlags() {
return Ci.nsIProtocolHandler.URI_NORELATIVE |
Ci.nsIProtocolHandler.URI_NOAUTH |
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE;
},
newURI(spec, originCharset, baseURI) {
let uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
uri.spec = spec;
return uri;
},
newChannel2(uri, loadInfo) {
try {
// Create a pipe that will give us an output stream that we can use once
// we got all the favicon data.
let pipe = Cc["@mozilla.org/pipe;1"]
.createInstance(Ci.nsIPipe);
pipe.init(true, true, 0, Ci.nsIFaviconService.MAX_FAVICON_BUFFER_SIZE);
// Create our channel.
let channel = Cc['@mozilla.org/network/input-stream-channel;1']
.createInstance(Ci.nsIInputStreamChannel);
channel.QueryInterface(Ci.nsIChannel);
channel.setURI(uri);
channel.contentStream = pipe.inputStream;
channel.loadInfo = loadInfo;
let pageURI = NetUtil.newURI(uri.path);
PlacesUtils.favicons.getFaviconDataForPage(pageURI, (iconuri, len, data, mime) => {
if (len == 0) {
channel.contentType = "image/png";
streamDefaultFavicon(uri, loadInfo, pipe.outputStream);
return;
}
try {
channel.contentType = mime;
channel.contentLength = len;
// Pass the icon data to the output stream.
let stream = Cc["@mozilla.org/binaryoutputstream;1"]
.createInstance(Ci.nsIBinaryOutputStream);
stream.setOutputStream(pipe.outputStream);
stream.writeByteArray(data, len);
stream.close();
pipe.outputStream.close();
} catch (ex) {
channel.contentType = "image/png";
streamDefaultFavicon(uri, loadInfo, pipe.outputStream);
}
});
return channel;
} catch (ex) {
return makeDefaultFaviconChannel(uri, loadInfo);
}
},
newChannel(uri) {
return this.newChannel2(uri, null);
},
allowPort(port, scheme) {
return false;
},
classID: Components.ID("{60a1f7c6-4ff9-4a42-84d3-5a185faa6f32}"),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIProtocolHandler
])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PageIconProtocolHandler]);
|