Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
* You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
"use strict";
6
7
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
8
ChromeUtils.defineModuleGetter(
9
this,
10
"PlacesUtils",
12
);
13
ChromeUtils.defineModuleGetter(
14
this,
15
"NetUtil",
17
);
18
19
function makeDefaultFaviconChannel(uri, loadInfo) {
20
let channel = Services.io.newChannelFromURIWithLoadInfo(
21
PlacesUtils.favicons.defaultFavicon,
22
loadInfo
23
);
24
channel.originalURI = uri;
25
channel.contentType = PlacesUtils.favicons.defaultFaviconMimeType;
26
return channel;
27
}
28
29
function streamDefaultFavicon(uri, loadInfo, outputStream, originalChannel) {
30
try {
31
// Open up a new channel to get that data, and push it to our output stream.
32
// Create a listener to hand data to the pipe's output stream.
33
let listener = Cc[
34
"@mozilla.org/network/simple-stream-listener;1"
35
].createInstance(Ci.nsISimpleStreamListener);
36
listener.init(outputStream, {
37
onStartRequest(request) {},
38
onStopRequest(request, statusCode) {
39
// We must close the outputStream regardless.
40
outputStream.close();
41
},
42
});
43
originalChannel.contentType = PlacesUtils.favicons.defaultFaviconMimeType;
44
let defaultIconChannel = makeDefaultFaviconChannel(uri, loadInfo);
45
defaultIconChannel.asyncOpen(listener);
46
} catch (ex) {
47
Cu.reportError(ex);
48
outputStream.close();
49
}
50
}
51
52
function serveIcon(pipe, data) {
53
// Pass the icon data to the output stream.
54
let stream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(
55
Ci.nsIBinaryOutputStream
56
);
57
stream.setOutputStream(pipe.outputStream);
58
stream.writeByteArray(data);
59
stream.close();
60
pipe.outputStream.close();
61
}
62
63
function PageIconProtocolHandler() {}
64
65
PageIconProtocolHandler.prototype = {
66
get scheme() {
67
return "page-icon";
68
},
69
70
get defaultPort() {
71
return -1;
72
},
73
74
get protocolFlags() {
75
return (
76
Ci.nsIProtocolHandler.URI_NORELATIVE |
77
Ci.nsIProtocolHandler.URI_NOAUTH |
78
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD |
79
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE
80
);
81
},
82
83
newChannel(uri, loadInfo) {
84
try {
85
// Create a pipe that will give us an output stream that we can use once
86
// we got all the favicon data.
87
let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
88
pipe.init(true, true, 0, Ci.nsIFaviconService.MAX_FAVICON_BUFFER_SIZE);
89
90
// Create our channel.
91
let channel = Cc[
92
"@mozilla.org/network/input-stream-channel;1"
93
].createInstance(Ci.nsIInputStreamChannel);
94
channel.QueryInterface(Ci.nsIChannel);
95
channel.setURI(uri);
96
channel.contentStream = pipe.inputStream;
97
channel.loadInfo = loadInfo;
98
99
let pageURI = NetUtil.newURI(
100
uri.pathQueryRef.replace(/[&#]size=[^&]+$/, "")
101
);
102
let preferredSize = PlacesUtils.favicons.preferredSizeFromURI(uri);
103
PlacesUtils.favicons.getFaviconDataForPage(
104
pageURI,
105
(iconURI, len, data, mimeType) => {
106
if (len == 0) {
107
streamDefaultFavicon(uri, loadInfo, pipe.outputStream, channel);
108
} else {
109
try {
110
channel.contentType = mimeType;
111
channel.contentLength = len;
112
if (len != data.length) {
113
throw new Error("Unexpected data length");
114
}
115
serveIcon(pipe, data);
116
} catch (ex) {
117
streamDefaultFavicon(uri, loadInfo, pipe.outputStream, channel);
118
}
119
}
120
},
121
preferredSize
122
);
123
124
return channel;
125
} catch (ex) {
126
return makeDefaultFaviconChannel(uri, loadInfo);
127
}
128
},
129
130
allowPort(port, scheme) {
131
return false;
132
},
133
134
classID: Components.ID("{60a1f7c6-4ff9-4a42-84d3-5a185faa6f32}"),
135
QueryInterface: ChromeUtils.generateQI([
136
Ci.nsIProtocolHandler,
137
Ci.nsISupportsWeakReference,
138
]),
139
};
140
141
var EXPORTED_SYMBOLS = ["PageIconProtocolHandler"];