-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathdiscover.js
88 lines (78 loc) · 2.17 KB
/
discover.js
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
var request = require('request')
, htmlparser = require('htmlparser2')
, parseHttpHeader = require('parse-http-header');
var feedTypes = [
'text/xml',
'application/rss+xml',
'application/atom+xml',
'application/rdf+xml'
];
module.exports = function (options, cb) {
var discovered = []
, contentType = ''
, url = 'string' === typeof options ? options : (options.url || options.uri)
, errored = false;
var req = this._request = request(options)
, parser = this._parser = new htmlparser.Stream();
req.on('error', onEnd);
req.on('abort', function () {
req.removeAllListeners();
req.destroy();
});
req.on('response', function (response) {
if (response.statusCode !== 200) {
var err = new Error(req.httpModule.STATUS_CODES[response.statusCode] || 'Unknown HTTP response');
err.code = response.statusCode;
return onEnd(err);
}
if (response.headers['content-type']) {
contentType = parseHttpHeader(response.headers['content-type'])[0];
}
if (~feedTypes.indexOf(contentType)) {
discovered.push({
rel: 'self',
type: contentType,
href: url
});
req.abort();
onEnd();
}
else {
req.pipe(parser);
}
});
parser.on('error', onEnd);
parser.on('finish', onEnd);
parser.on('opentag', function openHeadHandler (name) {
if (name === 'head') {
parser.removeListener('opentag', openHeadHandler);
parser.on('opentag', linkHandler);
parser.on('closetag', closeHeadHandler);
}
function linkHandler (name, attribs) {
if (name === 'link' && attribs && attribs.rel && attribs.rel === 'alternate') {
discovered.push(attribs);
}
}
function closeHeadHandler (name) {
if (name === 'head') {
parser.removeListener('opentag', linkHandler);
parser.removeListener('closetag', closeHeadHandler);
req.abort();
parser._parser.pause();
parser.end();
}
}
});
function onEnd (err) {
if (errored) return;
if (err) {
errored = true;
cb(err);
}
else {
cb(null, { 'content-type': contentType, 'links': discovered });
}
}
return this;
};