rdflib 2.2.21 → 2.2.22-b51259b5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rdflib.min.js +1 -1
- package/dist/rdflib.min.js.LICENSE.txt +9 -1
- package/dist/rdflib.min.js.map +1 -1
- package/esm/blank-node.js +61 -114
- package/esm/class-order.js +1 -1
- package/esm/collection.js +70 -128
- package/esm/convert.js +1 -2
- package/esm/default-graph.js +14 -48
- package/esm/empty.js +8 -39
- package/esm/factories/canonical-data-factory.js +33 -65
- package/esm/factories/extended-term-factory.js +18 -25
- package/esm/factories/factory-types.js +3 -2
- package/esm/factories/rdflib-data-factory.js +9 -19
- package/esm/fetcher.js +1341 -1854
- package/esm/formula.js +639 -846
- package/esm/index.js +40 -76
- package/esm/jsonldparser.js +24 -49
- package/esm/jsonparser.js +1 -8
- package/esm/lists.js +47 -110
- package/esm/literal.js +120 -189
- package/esm/log.js +7 -7
- package/esm/n3parser.js +1015 -1412
- package/esm/named-node.js +70 -119
- package/esm/namespace.js +2 -5
- package/esm/node-internal.js +73 -110
- package/esm/node.js +2 -7
- package/esm/parse.js +12 -19
- package/esm/patch-parser.js +10 -30
- package/esm/query-to-sparql.js +0 -18
- package/esm/query.js +63 -147
- package/esm/rdfaparser.js +794 -997
- package/esm/rdfxmlparser.js +347 -461
- package/esm/serialize.js +9 -27
- package/esm/serializer.js +820 -1049
- package/esm/sparql-to-query.js +44 -134
- package/esm/statement.js +54 -85
- package/esm/store.js +830 -1103
- package/esm/types.js +22 -21
- package/esm/update-manager.js +869 -1106
- package/esm/updates-via.js +104 -161
- package/esm/uri.js +9 -53
- package/esm/utils/default-graph-uri.js +3 -2
- package/esm/utils/termValue.js +0 -1
- package/esm/utils/terms.js +19 -21
- package/esm/utils-js.js +20 -61
- package/esm/utils.js +10 -21
- package/esm/variable.js +32 -78
- package/esm/xsd.js +2 -2
- package/lib/blank-node.js +60 -113
- package/lib/class-order.js +1 -2
- package/lib/collection.js +69 -131
- package/lib/convert.js +3 -9
- package/lib/default-graph.js +13 -52
- package/lib/empty.js +8 -43
- package/lib/factories/canonical-data-factory.js +35 -79
- package/lib/factories/extended-term-factory.js +18 -32
- package/lib/factories/factory-types.d.ts +6 -6
- package/lib/factories/factory-types.js +1 -4
- package/lib/factories/rdflib-data-factory.js +9 -23
- package/lib/fetcher.d.ts +6 -6
- package/lib/fetcher.js +1370 -1843
- package/lib/formula.js +640 -855
- package/lib/index.js +66 -152
- package/lib/jsonldparser.js +23 -53
- package/lib/jsonparser.js +1 -10
- package/lib/lists.js +55 -112
- package/lib/literal.js +120 -195
- package/lib/log.d.ts +0 -6
- package/lib/log.js +7 -8
- package/lib/n3parser.js +1030 -1436
- package/lib/named-node.js +69 -126
- package/lib/namespace.js +2 -7
- package/lib/node-internal.js +74 -107
- package/lib/node.js +2 -12
- package/lib/parse.d.ts +1 -1
- package/lib/parse.js +12 -32
- package/lib/patch-parser.js +11 -34
- package/lib/query-to-sparql.js +0 -23
- package/lib/query.js +62 -167
- package/lib/rdfaparser.js +796 -1009
- package/lib/rdfxmlparser.js +349 -466
- package/lib/serialize.js +11 -37
- package/lib/serializer.js +823 -1064
- package/lib/sparql-to-query.js +42 -167
- package/lib/statement.js +55 -91
- package/lib/store.d.ts +1 -1
- package/lib/store.js +850 -1112
- package/lib/tf-types.d.ts +4 -4
- package/lib/types.d.ts +8 -8
- package/lib/types.js +23 -23
- package/lib/update-manager.d.ts +1 -1
- package/lib/update-manager.js +865 -1103
- package/lib/updates-via.js +105 -164
- package/lib/uri.js +8 -61
- package/lib/utils/default-graph-uri.js +3 -5
- package/lib/utils/termValue.js +0 -2
- package/lib/utils/terms.js +19 -40
- package/lib/utils-js.js +23 -88
- package/lib/utils.js +10 -27
- package/lib/variable.js +34 -85
- package/lib/xsd-internal.js +0 -3
- package/lib/xsd.js +2 -6
- package/package.json +35 -35
- package/src/fetcher.ts +2 -2
- package/src/update-manager.ts +12 -7
- package/changes.txt +0 -59
package/lib/fetcher.js
CHANGED
|
@@ -1,80 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
-
|
|
7
4
|
Object.defineProperty(exports, "__esModule", {
|
|
8
5
|
value: true
|
|
9
6
|
});
|
|
10
7
|
exports.default = void 0;
|
|
11
|
-
|
|
12
|
-
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
13
|
-
|
|
14
|
-
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
15
|
-
|
|
16
|
-
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
17
|
-
|
|
18
|
-
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
19
|
-
|
|
20
|
-
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
21
|
-
|
|
22
|
-
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
23
|
-
|
|
24
|
-
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
25
|
-
|
|
26
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
27
|
-
|
|
28
9
|
var _store = _interopRequireDefault(require("./store"));
|
|
29
|
-
|
|
30
10
|
var _log = _interopRequireDefault(require("./log"));
|
|
31
|
-
|
|
32
11
|
var _n3parser = _interopRequireDefault(require("./n3parser"));
|
|
33
|
-
|
|
34
12
|
var _namedNode = _interopRequireDefault(require("./named-node"));
|
|
35
|
-
|
|
36
13
|
var _namespace = _interopRequireDefault(require("./namespace"));
|
|
37
|
-
|
|
38
14
|
var _parse = _interopRequireDefault(require("./parse"));
|
|
39
|
-
|
|
40
15
|
var _rdfaparser = require("./rdfaparser");
|
|
41
|
-
|
|
42
16
|
var _rdfxmlparser = _interopRequireDefault(require("./rdfxmlparser"));
|
|
43
|
-
|
|
44
17
|
var Uri = _interopRequireWildcard(require("./uri"));
|
|
45
|
-
|
|
46
18
|
var _terms = require("./utils/terms");
|
|
47
|
-
|
|
48
19
|
var Util = _interopRequireWildcard(require("./utils-js"));
|
|
49
|
-
|
|
50
20
|
var _serialize = _interopRequireDefault(require("./serialize"));
|
|
51
|
-
|
|
52
21
|
var _crossFetch = _interopRequireWildcard(require("cross-fetch"));
|
|
53
|
-
|
|
54
22
|
var _types = require("./types");
|
|
55
|
-
|
|
56
23
|
var _termValue = require("./utils/termValue");
|
|
57
|
-
|
|
58
24
|
var _jsonldparser = _interopRequireDefault(require("./jsonldparser"));
|
|
25
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
26
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
27
|
+
/* global $SolidTestEnvironment */
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* Project: rdflib.js
|
|
31
|
+
*
|
|
32
|
+
* @file: fetcher.js
|
|
33
|
+
*
|
|
34
|
+
* Description: contains functions for requesting/fetching/retracting
|
|
35
|
+
* This implements quite a lot of the web architecture.
|
|
36
|
+
* A fetcher is bound to a specific quad store, into which
|
|
37
|
+
* it loads stuff and into which it writes its metadata
|
|
38
|
+
* @@ The metadata could be optionally a separate graph
|
|
39
|
+
*
|
|
40
|
+
* - implements semantics of HTTP headers, Internet Content Types
|
|
41
|
+
* - selects parsers for rdf/xml, n3, rdfa, grddl
|
|
42
|
+
*
|
|
43
|
+
* TO do:
|
|
44
|
+
* - Implement a runtime registry for parsers and serializers
|
|
45
|
+
* -
|
|
46
|
+
*/
|
|
59
47
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
|
|
48
|
+
/**
|
|
49
|
+
* Things to test: callbacks on request, refresh, retract
|
|
50
|
+
* loading from HTTP, HTTPS, FTP, FILE, others?
|
|
51
|
+
* To do:
|
|
52
|
+
* Firing up a mail client for mid: (message:) URLs
|
|
53
|
+
*/
|
|
67
54
|
|
|
68
|
-
|
|
55
|
+
const Parsable = {
|
|
69
56
|
'text/n3': true,
|
|
70
57
|
'text/turtle': true,
|
|
71
58
|
'application/rdf+xml': true,
|
|
72
59
|
'application/xhtml+xml': true,
|
|
73
60
|
'text/html': true,
|
|
74
61
|
'application/ld+json': true
|
|
75
|
-
};
|
|
62
|
+
};
|
|
76
63
|
|
|
77
|
-
|
|
64
|
+
// This is a minimal set to allow the use of damaged servers if necessary
|
|
65
|
+
const CONTENT_TYPE_BY_EXT = {
|
|
78
66
|
'rdf': _types.RDFXMLContentType,
|
|
79
67
|
'owl': _types.RDFXMLContentType,
|
|
80
68
|
'n3': 'text/n3',
|
|
@@ -83,13 +71,14 @@ var CONTENT_TYPE_BY_EXT = {
|
|
|
83
71
|
'acl': 'text/n3',
|
|
84
72
|
'html': 'text/html',
|
|
85
73
|
'xml': 'text/xml'
|
|
86
|
-
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Convenience namespaces needed in this module.
|
|
87
77
|
// These are deliberately not exported as the user application should
|
|
88
78
|
// make its own list and not rely on the prefixes used here,
|
|
89
79
|
// and not be tempted to add to them, and them clash with those of another
|
|
90
80
|
// application.
|
|
91
|
-
|
|
92
|
-
var getNS = function getNS(factory) {
|
|
81
|
+
const getNS = factory => {
|
|
93
82
|
return {
|
|
94
83
|
link: (0, _namespace.default)('http://www.w3.org/2007/ont/link#', factory),
|
|
95
84
|
http: (0, _namespace.default)('http://www.w3.org/2007/ont/http#', factory),
|
|
@@ -101,520 +90,351 @@ var getNS = function getNS(factory) {
|
|
|
101
90
|
ldp: (0, _namespace.default)('http://www.w3.org/ns/ldp#', factory)
|
|
102
91
|
};
|
|
103
92
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
93
|
+
const ns = getNS();
|
|
94
|
+
class Handler {
|
|
95
|
+
// TODO: Document, type
|
|
96
|
+
|
|
97
|
+
// TODO: Document, type
|
|
98
|
+
|
|
99
|
+
constructor(response, dom) {
|
|
100
|
+
(0, _defineProperty2.default)(this, "response", void 0);
|
|
101
|
+
(0, _defineProperty2.default)(this, "dom", void 0);
|
|
102
|
+
this.response = response;
|
|
103
|
+
// The type assertion operator here might need to be removed.
|
|
104
|
+
this.dom = dom;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
116
107
|
(0, _defineProperty2.default)(Handler, "pattern", void 0);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
var _super = _createSuper(RDFXMLHandler);
|
|
122
|
-
|
|
123
|
-
function RDFXMLHandler() {
|
|
124
|
-
(0, _classCallCheck2.default)(this, RDFXMLHandler);
|
|
125
|
-
return _super.apply(this, arguments);
|
|
108
|
+
class RDFXMLHandler extends Handler {
|
|
109
|
+
static toString() {
|
|
110
|
+
return 'RDFXMLHandler';
|
|
126
111
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (!options.noMeta) {
|
|
158
|
-
kb.add(options.original, ns.rdf('type'), ns.link('RDFDocument'), fetcher.appNode);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return fetcher.doneFetch(options, this.response);
|
|
162
|
-
}
|
|
163
|
-
}], [{
|
|
164
|
-
key: "toString",
|
|
165
|
-
value: function toString() {
|
|
166
|
-
return 'RDFXMLHandler';
|
|
167
|
-
}
|
|
168
|
-
}, {
|
|
169
|
-
key: "register",
|
|
170
|
-
value: function register(fetcher) {
|
|
171
|
-
fetcher.mediatypes[_types.RDFXMLContentType] = {
|
|
172
|
-
'q': 0.9
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
}]);
|
|
176
|
-
return RDFXMLHandler;
|
|
177
|
-
}(Handler);
|
|
178
|
-
|
|
112
|
+
static register(fetcher) {
|
|
113
|
+
fetcher.mediatypes[_types.RDFXMLContentType] = {
|
|
114
|
+
'q': 0.9
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
parse(fetcher, /** An XML String */
|
|
118
|
+
responseText, /** Requires .original */
|
|
119
|
+
options) {
|
|
120
|
+
let kb = fetcher.store;
|
|
121
|
+
if (!this.dom) {
|
|
122
|
+
this.dom = Util.parseXML(responseText);
|
|
123
|
+
}
|
|
124
|
+
let root = this.dom.documentElement;
|
|
125
|
+
if (root.nodeName === 'parsererror') {
|
|
126
|
+
// Mozilla only See issue/issue110
|
|
127
|
+
// have to fail the request
|
|
128
|
+
return fetcher.failFetch(options, 'Badly formed XML in ' + options.resource.value, 'parse_error');
|
|
129
|
+
}
|
|
130
|
+
let parser = new _rdfxmlparser.default(kb);
|
|
131
|
+
try {
|
|
132
|
+
parser.parse(this.dom, options.original.value, options.original);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
return fetcher.failFetch(options, 'Syntax error parsing RDF/XML! ' + err, 'parse_error');
|
|
135
|
+
}
|
|
136
|
+
if (!options.noMeta) {
|
|
137
|
+
kb.add(options.original, ns.rdf('type'), ns.link('RDFDocument'), fetcher.appNode);
|
|
138
|
+
}
|
|
139
|
+
return fetcher.doneFetch(options, this.response);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
179
142
|
RDFXMLHandler.pattern = new RegExp('application/rdf\\+xml');
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
var _super2 = _createSuper(XHTMLHandler);
|
|
185
|
-
|
|
186
|
-
function XHTMLHandler() {
|
|
187
|
-
(0, _classCallCheck2.default)(this, XHTMLHandler);
|
|
188
|
-
return _super2.apply(this, arguments);
|
|
143
|
+
class XHTMLHandler extends Handler {
|
|
144
|
+
static toString() {
|
|
145
|
+
return 'XHTMLHandler';
|
|
189
146
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (!relation) {
|
|
217
|
-
relation = links[x].getAttribute('rev');
|
|
218
|
-
reverse = true;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if (relation) {
|
|
222
|
-
fetcher.linkData(options.original, relation, links[x].getAttribute('href'), options.resource, reverse);
|
|
223
|
-
}
|
|
224
|
-
} // Data Islands
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
var scripts = this.dom.getElementsByTagName('script');
|
|
228
|
-
|
|
229
|
-
for (var i = 0; i < scripts.length; i++) {
|
|
230
|
-
var contentType = scripts[i].getAttribute('type');
|
|
231
|
-
|
|
232
|
-
if (Parsable[contentType]) {
|
|
233
|
-
// @ts-ignore incompatibility between Store.add and Formula.add
|
|
234
|
-
(0, _parse.default)(scripts[i].textContent, kb, options.original.value, contentType); // @ts-ignore incompatibility between Store.add and Formula.add
|
|
235
|
-
|
|
236
|
-
(0, _parse.default)(scripts[i].textContent, kb, options.original.value, contentType);
|
|
237
|
-
}
|
|
147
|
+
static register(fetcher) {
|
|
148
|
+
fetcher.mediatypes[_types.XHTMLContentType] = {};
|
|
149
|
+
}
|
|
150
|
+
parse(fetcher, responseText, options) {
|
|
151
|
+
let relation, reverse;
|
|
152
|
+
if (!this.dom) {
|
|
153
|
+
this.dom = Util.parseXML(responseText);
|
|
154
|
+
}
|
|
155
|
+
let kb = fetcher.store;
|
|
156
|
+
|
|
157
|
+
// dc:title
|
|
158
|
+
let title = this.dom.getElementsByTagName('title');
|
|
159
|
+
if (title.length > 0) {
|
|
160
|
+
kb.add(options.resource, ns.dc('title'), kb.rdfFactory.literal(title[0].textContent), options.resource);
|
|
161
|
+
// log.info("Inferring title of " + xhr.resource)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// link rel
|
|
165
|
+
let links = this.dom.getElementsByTagName('link');
|
|
166
|
+
for (let x = links.length - 1; x >= 0; x--) {
|
|
167
|
+
// @@ rev
|
|
168
|
+
relation = links[x].getAttribute('rel');
|
|
169
|
+
reverse = false;
|
|
170
|
+
if (!relation) {
|
|
171
|
+
relation = links[x].getAttribute('rev');
|
|
172
|
+
reverse = true;
|
|
238
173
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
kb.add(options.resource, ns.rdf('type'), ns.link('WebPage'), fetcher.appNode);
|
|
174
|
+
if (relation) {
|
|
175
|
+
fetcher.linkData(options.original, relation, links[x].getAttribute('href'), options.resource, reverse);
|
|
242
176
|
}
|
|
177
|
+
}
|
|
243
178
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
179
|
+
// Data Islands
|
|
180
|
+
let scripts = this.dom.getElementsByTagName('script');
|
|
181
|
+
for (let i = 0; i < scripts.length; i++) {
|
|
182
|
+
let contentType = scripts[i].getAttribute('type');
|
|
183
|
+
if (Parsable[contentType]) {
|
|
184
|
+
// @ts-ignore incompatibility between Store.add and Formula.add
|
|
185
|
+
(0, _parse.default)(scripts[i].textContent, kb, options.original.value, contentType);
|
|
186
|
+
// @ts-ignore incompatibility between Store.add and Formula.add
|
|
187
|
+
(0, _parse.default)(scripts[i].textContent, kb, options.original.value, contentType);
|
|
253
188
|
}
|
|
254
|
-
|
|
255
|
-
return fetcher.doneFetch(options, this.response);
|
|
256
189
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
value: function toString() {
|
|
260
|
-
return 'XHTMLHandler';
|
|
190
|
+
if (!options.noMeta) {
|
|
191
|
+
kb.add(options.resource, ns.rdf('type'), ns.link('WebPage'), fetcher.appNode);
|
|
261
192
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
193
|
+
if (!options.noRDFa && _rdfaparser.parseRDFaDOM) {
|
|
194
|
+
// enable by default
|
|
195
|
+
try {
|
|
196
|
+
(0, _rdfaparser.parseRDFaDOM)(this.dom, kb, options.original.value);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
// @ts-ignore
|
|
199
|
+
let msg = 'Error trying to parse ' + options.resource + ' as RDFa:\n' + err + ':\n' + err.stack;
|
|
200
|
+
return fetcher.failFetch(options, msg, 'parse_error');
|
|
201
|
+
}
|
|
266
202
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
|
|
203
|
+
return fetcher.doneFetch(options, this.response);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
271
206
|
XHTMLHandler.pattern = new RegExp('application/xhtml');
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
var _super3 = _createSuper(XMLHandler);
|
|
277
|
-
|
|
278
|
-
function XMLHandler() {
|
|
279
|
-
(0, _classCallCheck2.default)(this, XMLHandler);
|
|
280
|
-
return _super3.apply(this, arguments);
|
|
207
|
+
class XMLHandler extends Handler {
|
|
208
|
+
static toString() {
|
|
209
|
+
return 'XMLHandler';
|
|
281
210
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (dom.doctype.name === 'html' && dom.doctype.publicId.match(/^-\/\/W3C\/\/DTD XHTML/) && dom.doctype.systemId.match(/http:\/\/www.w3.org\/TR\/xhtml/)) {
|
|
311
|
-
fetcher.addStatus(options.req, 'Has XHTML DOCTYPE. Switching to XHTML Handler.\n');
|
|
312
|
-
var xhtmlHandler = new XHTMLHandler(this.response, dom);
|
|
313
|
-
return xhtmlHandler.parse(fetcher, responseText, options);
|
|
314
|
-
}
|
|
315
|
-
} // Or what about an XHTML namespace?
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
var html = dom.getElementsByTagName('html')[0];
|
|
319
|
-
|
|
320
|
-
if (html) {
|
|
321
|
-
var xmlns = html.getAttribute('xmlns');
|
|
322
|
-
|
|
323
|
-
if (xmlns && xmlns.match(/^http:\/\/www.w3.org\/1999\/xhtml/)) {
|
|
324
|
-
fetcher.addStatus(options.req, 'Has a default namespace for ' + 'XHTML. Switching to XHTMLHandler.\n');
|
|
325
|
-
|
|
326
|
-
var _xhtmlHandler = new XHTMLHandler(this.response, dom);
|
|
327
|
-
|
|
328
|
-
return _xhtmlHandler.parse(fetcher, responseText, options);
|
|
211
|
+
static register(fetcher) {
|
|
212
|
+
fetcher.mediatypes['text/xml'] = {
|
|
213
|
+
'q': 0.5
|
|
214
|
+
};
|
|
215
|
+
fetcher.mediatypes['application/xml'] = {
|
|
216
|
+
'q': 0.5
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
static isElement(node) {
|
|
220
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
221
|
+
}
|
|
222
|
+
parse(fetcher, responseText, options) {
|
|
223
|
+
let dom = Util.parseXML(responseText);
|
|
224
|
+
|
|
225
|
+
// XML Semantics defined by root element namespace
|
|
226
|
+
// figure out the root element
|
|
227
|
+
for (let c = 0; c < dom.childNodes.length; c++) {
|
|
228
|
+
const node = dom.childNodes[c];
|
|
229
|
+
// is this node an element?
|
|
230
|
+
if (XMLHandler.isElement(node)) {
|
|
231
|
+
// We've found the first element, it's the root
|
|
232
|
+
let ns = node.namespaceURI;
|
|
233
|
+
|
|
234
|
+
// Is it RDF/XML?
|
|
235
|
+
if (ns && ns === ns['rdf']) {
|
|
236
|
+
fetcher.addStatus(options.req, 'Has XML root element in the RDF namespace, so assume RDF/XML.');
|
|
237
|
+
let rdfHandler = new RDFXMLHandler(this.response, dom);
|
|
238
|
+
return rdfHandler.parse(fetcher, responseText, options);
|
|
329
239
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
// @@ Get namespace document <n>, parse it, look for <n> grddl:namespaceTransform ?y
|
|
333
|
-
// Apply ?y to dom
|
|
334
|
-
// We give up. What dialect is this?
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return fetcher.failFetch(options, 'Unsupported dialect of XML: not RDF or XHTML namespace, etc.\n' + responseText.slice(0, 80), 901);
|
|
338
|
-
}
|
|
339
|
-
}], [{
|
|
340
|
-
key: "toString",
|
|
341
|
-
value: function toString() {
|
|
342
|
-
return 'XMLHandler';
|
|
343
|
-
}
|
|
344
|
-
}, {
|
|
345
|
-
key: "register",
|
|
346
|
-
value: function register(fetcher) {
|
|
347
|
-
fetcher.mediatypes['text/xml'] = {
|
|
348
|
-
'q': 0.5
|
|
349
|
-
};
|
|
350
|
-
fetcher.mediatypes['application/xml'] = {
|
|
351
|
-
'q': 0.5
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
}, {
|
|
355
|
-
key: "isElement",
|
|
356
|
-
value: function isElement(node) {
|
|
357
|
-
return node.nodeType === Node.ELEMENT_NODE;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
358
242
|
}
|
|
359
|
-
}]);
|
|
360
|
-
return XMLHandler;
|
|
361
|
-
}(Handler);
|
|
362
|
-
|
|
363
|
-
XMLHandler.pattern = new RegExp('(text|application)/(.*)xml');
|
|
364
|
-
|
|
365
|
-
var HTMLHandler = /*#__PURE__*/function (_Handler4) {
|
|
366
|
-
(0, _inherits2.default)(HTMLHandler, _Handler4);
|
|
367
|
-
|
|
368
|
-
var _super4 = _createSuper(HTMLHandler);
|
|
369
|
-
|
|
370
|
-
function HTMLHandler() {
|
|
371
|
-
(0, _classCallCheck2.default)(this, HTMLHandler);
|
|
372
|
-
return _super4.apply(this, arguments);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
(0, _createClass2.default)(HTMLHandler, [{
|
|
376
|
-
key: "parse",
|
|
377
|
-
value: function parse(fetcher, responseText, options) {
|
|
378
|
-
var kb = fetcher.store; // We only handle XHTML so we have to figure out if this is XML
|
|
379
|
-
// log.info("Sniffing HTML " + xhr.resource + " for XHTML.")
|
|
380
243
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
244
|
+
// Or it could be XHTML?
|
|
245
|
+
// Maybe it has an XHTML DOCTYPE?
|
|
246
|
+
if (dom.doctype) {
|
|
247
|
+
// log.info("We found a DOCTYPE in " + xhr.resource)
|
|
248
|
+
if (dom.doctype.name === 'html' && dom.doctype.publicId.match(/^-\/\/W3C\/\/DTD XHTML/) && dom.doctype.systemId.match(/http:\/\/www.w3.org\/TR\/xhtml/)) {
|
|
249
|
+
fetcher.addStatus(options.req, 'Has XHTML DOCTYPE. Switching to XHTML Handler.\n');
|
|
250
|
+
let xhtmlHandler = new XHTMLHandler(this.response, dom);
|
|
384
251
|
return xhtmlHandler.parse(fetcher, responseText, options);
|
|
385
|
-
} // DOCTYPE html
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if (isXHTML(responseText)) {
|
|
389
|
-
fetcher.addStatus(options.req, 'Has XHTML DOCTYPE. Switching to XHTMLHandler.\n');
|
|
390
|
-
|
|
391
|
-
var _xhtmlHandler2 = new XHTMLHandler(this.response);
|
|
392
|
-
|
|
393
|
-
return _xhtmlHandler2.parse(fetcher, responseText, options);
|
|
394
|
-
} // xmlns
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
if (isXMLNS(responseText)) {
|
|
398
|
-
fetcher.addStatus(options.req, 'Has default namespace for XHTML, so switching to XHTMLHandler.\n');
|
|
399
|
-
|
|
400
|
-
var _xhtmlHandler3 = new XHTMLHandler(this.response);
|
|
401
|
-
|
|
402
|
-
return _xhtmlHandler3.parse(fetcher, responseText, options);
|
|
403
|
-
} // dc:title
|
|
404
|
-
// no need to escape '/' here
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
var titleMatch = new RegExp('<title>([\\s\\S]+?)</title>', 'im').exec(responseText);
|
|
408
|
-
|
|
409
|
-
if (titleMatch) {
|
|
410
|
-
kb.add(options.resource, ns.dc('title'), kb.rdfFactory.literal(titleMatch[1]), options.resource); // think about xml:lang later
|
|
411
252
|
}
|
|
412
|
-
|
|
413
|
-
kb.add(options.resource, ns.rdf('type'), ns.link('WebPage'), fetcher.appNode);
|
|
414
|
-
fetcher.addStatus(options.req, 'non-XML HTML document, not parsed for data.');
|
|
415
|
-
return fetcher.doneFetch(options, this.response);
|
|
416
|
-
}
|
|
417
|
-
}], [{
|
|
418
|
-
key: "toString",
|
|
419
|
-
value: function toString() {
|
|
420
|
-
return 'HTMLHandler';
|
|
421
|
-
}
|
|
422
|
-
}, {
|
|
423
|
-
key: "register",
|
|
424
|
-
value: function register(fetcher) {
|
|
425
|
-
fetcher.mediatypes['text/html'] = {
|
|
426
|
-
'q': 0.9
|
|
427
|
-
};
|
|
428
253
|
}
|
|
429
|
-
}]);
|
|
430
|
-
return HTMLHandler;
|
|
431
|
-
}(Handler);
|
|
432
|
-
|
|
433
|
-
HTMLHandler.pattern = new RegExp('text/html');
|
|
434
|
-
|
|
435
|
-
var JsonLdHandler = /*#__PURE__*/function (_Handler5) {
|
|
436
|
-
(0, _inherits2.default)(JsonLdHandler, _Handler5);
|
|
437
|
-
|
|
438
|
-
var _super5 = _createSuper(JsonLdHandler);
|
|
439
|
-
|
|
440
|
-
function JsonLdHandler() {
|
|
441
|
-
(0, _classCallCheck2.default)(this, JsonLdHandler);
|
|
442
|
-
return _super5.apply(this, arguments);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
(0, _createClass2.default)(JsonLdHandler, [{
|
|
446
|
-
key: "parse",
|
|
447
|
-
value: function parse(fetcher, responseText, options, response) {
|
|
448
|
-
var kb = fetcher.store;
|
|
449
|
-
return new Promise(function (resolve, reject) {
|
|
450
|
-
try {
|
|
451
|
-
(0, _jsonldparser.default)(responseText, kb, options.original.value, function () {
|
|
452
|
-
resolve(fetcher.doneFetch(options, response));
|
|
453
|
-
});
|
|
454
|
-
} catch (err) {
|
|
455
|
-
var msg = 'Error trying to parse ' + options.resource + ' as JSON-LD:\n' + err; // not err.stack -- irrelevant
|
|
456
254
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}, {
|
|
467
|
-
key: "register",
|
|
468
|
-
value: function register(fetcher) {
|
|
469
|
-
fetcher.mediatypes['application/ld+json'] = {
|
|
470
|
-
'q': 0.9
|
|
471
|
-
};
|
|
255
|
+
// Or what about an XHTML namespace?
|
|
256
|
+
let html = dom.getElementsByTagName('html')[0];
|
|
257
|
+
if (html) {
|
|
258
|
+
let xmlns = html.getAttribute('xmlns');
|
|
259
|
+
if (xmlns && xmlns.match(/^http:\/\/www.w3.org\/1999\/xhtml/)) {
|
|
260
|
+
fetcher.addStatus(options.req, 'Has a default namespace for ' + 'XHTML. Switching to XHTMLHandler.\n');
|
|
261
|
+
let xhtmlHandler = new XHTMLHandler(this.response, dom);
|
|
262
|
+
return xhtmlHandler.parse(fetcher, responseText, options);
|
|
263
|
+
}
|
|
472
264
|
}
|
|
473
|
-
}]);
|
|
474
|
-
return JsonLdHandler;
|
|
475
|
-
}(Handler);
|
|
476
|
-
|
|
477
|
-
JsonLdHandler.pattern = /application\/ld\+json/;
|
|
478
|
-
|
|
479
|
-
var TextHandler = /*#__PURE__*/function (_Handler6) {
|
|
480
|
-
(0, _inherits2.default)(TextHandler, _Handler6);
|
|
481
265
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
266
|
+
// At this point we should check the namespace document (cache it!) and
|
|
267
|
+
// look for a GRDDL transform
|
|
268
|
+
// @@ Get namespace document <n>, parse it, look for <n> grddl:namespaceTransform ?y
|
|
269
|
+
// Apply ?y to dom
|
|
270
|
+
// We give up. What dialect is this?
|
|
271
|
+
return fetcher.failFetch(options, 'Unsupported dialect of XML: not RDF or XHTML namespace, etc.\n' + responseText.slice(0, 80), 901);
|
|
487
272
|
}
|
|
273
|
+
}
|
|
274
|
+
XMLHandler.pattern = new RegExp('(text|application)/(.*)xml');
|
|
275
|
+
class HTMLHandler extends Handler {
|
|
276
|
+
static toString() {
|
|
277
|
+
return 'HTMLHandler';
|
|
278
|
+
}
|
|
279
|
+
static register(fetcher) {
|
|
280
|
+
fetcher.mediatypes['text/html'] = {
|
|
281
|
+
'q': 0.9
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
parse(fetcher, responseText, options) {
|
|
285
|
+
let kb = fetcher.store;
|
|
488
286
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
fetcher.addStatus(options.req, 'Warning: ' + options.resource + " has an XML declaration. We'll assume " + "it's XML but its content-type wasn't XML.\n");
|
|
496
|
-
var xmlHandler = new XMLHandler(this.response);
|
|
497
|
-
return xmlHandler.parse(fetcher, responseText, options);
|
|
498
|
-
} // Look for an XML declaration
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
if (responseText.slice(0, 500).match(/xmlns:/)) {
|
|
502
|
-
fetcher.addStatus(options.req, "May have an XML namespace. We'll assume " + "it's XML but its content-type wasn't XML.\n");
|
|
503
|
-
|
|
504
|
-
var _xmlHandler = new XMLHandler(this.response);
|
|
505
|
-
|
|
506
|
-
return _xmlHandler.parse(fetcher, responseText, options);
|
|
507
|
-
} // We give up finding semantics - this is not an error, just no data
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
fetcher.addStatus(options.req, 'Plain text document, no known RDF semantics.');
|
|
511
|
-
return fetcher.doneFetch(options, this.response);
|
|
512
|
-
}
|
|
513
|
-
}], [{
|
|
514
|
-
key: "toString",
|
|
515
|
-
value: function toString() {
|
|
516
|
-
return 'TextHandler';
|
|
287
|
+
// We only handle XHTML so we have to figure out if this is XML
|
|
288
|
+
// log.info("Sniffing HTML " + xhr.resource + " for XHTML.")
|
|
289
|
+
if (isXML(responseText)) {
|
|
290
|
+
fetcher.addStatus(options.req, "Has an XML declaration. We'll assume " + "it's XHTML as the content-type was text/html.\n");
|
|
291
|
+
let xhtmlHandler = new XHTMLHandler(this.response);
|
|
292
|
+
return xhtmlHandler.parse(fetcher, responseText, options);
|
|
517
293
|
}
|
|
518
|
-
}, {
|
|
519
|
-
key: "register",
|
|
520
|
-
value: function register(fetcher) {
|
|
521
|
-
fetcher.mediatypes['text/plain'] = {
|
|
522
|
-
'q': 0.5
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
}]);
|
|
526
|
-
return TextHandler;
|
|
527
|
-
}(Handler);
|
|
528
294
|
|
|
529
|
-
|
|
295
|
+
// DOCTYPE html
|
|
296
|
+
if (isXHTML(responseText)) {
|
|
297
|
+
fetcher.addStatus(options.req, 'Has XHTML DOCTYPE. Switching to XHTMLHandler.\n');
|
|
298
|
+
let xhtmlHandler = new XHTMLHandler(this.response);
|
|
299
|
+
return xhtmlHandler.parse(fetcher, responseText, options);
|
|
300
|
+
}
|
|
530
301
|
|
|
531
|
-
|
|
532
|
-
|
|
302
|
+
// xmlns
|
|
303
|
+
if (isXMLNS(responseText)) {
|
|
304
|
+
fetcher.addStatus(options.req, 'Has default namespace for XHTML, so switching to XHTMLHandler.\n');
|
|
305
|
+
let xhtmlHandler = new XHTMLHandler(this.response);
|
|
306
|
+
return xhtmlHandler.parse(fetcher, responseText, options);
|
|
307
|
+
}
|
|
533
308
|
|
|
534
|
-
|
|
309
|
+
// dc:title
|
|
310
|
+
// no need to escape '/' here
|
|
311
|
+
let titleMatch = new RegExp('<title>([\\s\\S]+?)</title>', 'im').exec(responseText);
|
|
312
|
+
if (titleMatch) {
|
|
313
|
+
kb.add(options.resource, ns.dc('title'), kb.rdfFactory.literal(titleMatch[1]), options.resource); // think about xml:lang later
|
|
314
|
+
}
|
|
535
315
|
|
|
536
|
-
|
|
537
|
-
(
|
|
538
|
-
return
|
|
316
|
+
kb.add(options.resource, ns.rdf('type'), ns.link('WebPage'), fetcher.appNode);
|
|
317
|
+
fetcher.addStatus(options.req, 'non-XML HTML document, not parsed for data.');
|
|
318
|
+
return fetcher.doneFetch(options, this.response);
|
|
539
319
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
320
|
+
}
|
|
321
|
+
HTMLHandler.pattern = new RegExp('text/html');
|
|
322
|
+
class JsonLdHandler extends Handler {
|
|
323
|
+
static toString() {
|
|
324
|
+
return 'JsonLdHandler';
|
|
325
|
+
}
|
|
326
|
+
static register(fetcher) {
|
|
327
|
+
fetcher.mediatypes['application/ld+json'] = {
|
|
328
|
+
'q': 0.9
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
parse(fetcher, responseText, options, response) {
|
|
332
|
+
const kb = fetcher.store;
|
|
333
|
+
return new Promise((resolve, reject) => {
|
|
548
334
|
try {
|
|
549
|
-
|
|
335
|
+
(0, _jsonldparser.default)(responseText, kb, options.original.value, () => {
|
|
336
|
+
resolve(fetcher.doneFetch(options, response));
|
|
337
|
+
});
|
|
550
338
|
} catch (err) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return fetcher.failFetch(options, msg, 'parse_error', response);
|
|
339
|
+
const msg = 'Error trying to parse ' + options.resource + ' as JSON-LD:\n' + err; // not err.stack -- irrelevant
|
|
340
|
+
resolve(fetcher.failFetch(options, msg, 'parse_error', response));
|
|
554
341
|
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
JsonLdHandler.pattern = /application\/ld\+json/;
|
|
346
|
+
class TextHandler extends Handler {
|
|
347
|
+
static toString() {
|
|
348
|
+
return 'TextHandler';
|
|
349
|
+
}
|
|
350
|
+
static register(fetcher) {
|
|
351
|
+
fetcher.mediatypes['text/plain'] = {
|
|
352
|
+
'q': 0.5
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
parse(fetcher, responseText, options) {
|
|
356
|
+
// We only speak dialects of XML right now. Is this XML?
|
|
555
357
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
358
|
+
// Look for an XML declaration
|
|
359
|
+
if (isXML(responseText)) {
|
|
360
|
+
fetcher.addStatus(options.req, 'Warning: ' + options.resource + " has an XML declaration. We'll assume " + "it's XML but its content-type wasn't XML.\n");
|
|
361
|
+
let xmlHandler = new XMLHandler(this.response);
|
|
362
|
+
return xmlHandler.parse(fetcher, responseText, options);
|
|
559
363
|
}
|
|
560
|
-
}], [{
|
|
561
|
-
key: "toString",
|
|
562
|
-
value: function toString() {
|
|
563
|
-
return 'N3Handler';
|
|
564
|
-
}
|
|
565
|
-
}, {
|
|
566
|
-
key: "register",
|
|
567
|
-
value: function register(fetcher) {
|
|
568
|
-
fetcher.mediatypes['text/n3'] = {
|
|
569
|
-
'q': '1.0'
|
|
570
|
-
}; // as per 2008 spec
|
|
571
|
-
|
|
572
|
-
/*
|
|
573
|
-
fetcher.mediatypes['application/x-turtle'] = {
|
|
574
|
-
'q': 1.0
|
|
575
|
-
} // pre 2008
|
|
576
|
-
*/
|
|
577
364
|
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
365
|
+
// Look for an XML declaration
|
|
366
|
+
if (responseText.slice(0, 500).match(/xmlns:/)) {
|
|
367
|
+
fetcher.addStatus(options.req, "May have an XML namespace. We'll assume " + "it's XML but its content-type wasn't XML.\n");
|
|
368
|
+
let xmlHandler = new XMLHandler(this.response);
|
|
369
|
+
return xmlHandler.parse(fetcher, responseText, options);
|
|
581
370
|
}
|
|
582
|
-
}]);
|
|
583
|
-
return N3Handler;
|
|
584
|
-
}(Handler);
|
|
585
371
|
|
|
372
|
+
// We give up finding semantics - this is not an error, just no data
|
|
373
|
+
fetcher.addStatus(options.req, 'Plain text document, no known RDF semantics.');
|
|
374
|
+
return fetcher.doneFetch(options, this.response);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
TextHandler.pattern = new RegExp('text/plain');
|
|
378
|
+
class N3Handler extends Handler {
|
|
379
|
+
static toString() {
|
|
380
|
+
return 'N3Handler';
|
|
381
|
+
}
|
|
382
|
+
static register(fetcher) {
|
|
383
|
+
fetcher.mediatypes['text/n3'] = {
|
|
384
|
+
'q': '1.0'
|
|
385
|
+
}; // as per 2008 spec
|
|
386
|
+
/*
|
|
387
|
+
fetcher.mediatypes['application/x-turtle'] = {
|
|
388
|
+
'q': 1.0
|
|
389
|
+
} // pre 2008
|
|
390
|
+
*/
|
|
391
|
+
fetcher.mediatypes['text/turtle'] = {
|
|
392
|
+
'q': 1.0
|
|
393
|
+
}; // post 2008
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
parse(fetcher, responseText, options, response) {
|
|
397
|
+
// Parse the text of this N3 file
|
|
398
|
+
let kb = fetcher.store;
|
|
399
|
+
let p = (0, _n3parser.default)(kb, kb, options.original.value, options.original.value, null, null, '', null);
|
|
400
|
+
// p.loadBuf(xhr.responseText)
|
|
401
|
+
try {
|
|
402
|
+
p.loadBuf(responseText);
|
|
403
|
+
} catch (err) {
|
|
404
|
+
let msg = 'Error trying to parse ' + options.resource + ' as Notation3:\n' + err; // not err.stack -- irrelevant
|
|
405
|
+
return fetcher.failFetch(options, msg, 'parse_error', response);
|
|
406
|
+
}
|
|
407
|
+
fetcher.addStatus(options.req, 'N3 parsed: ' + p.statementCount + ' triples in ' + p.lines + ' lines.');
|
|
408
|
+
fetcher.store.add(options.original, ns.rdf('type'), ns.link('RDFDocument'), fetcher.appNode);
|
|
409
|
+
return fetcher.doneFetch(options, this.response);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
586
412
|
N3Handler.pattern = new RegExp('(application|text)/(x-)?(rdf\\+)?(n3|turtle)');
|
|
587
|
-
|
|
588
|
-
RDFXMLHandler
|
|
589
|
-
XHTMLHandler
|
|
590
|
-
XMLHandler
|
|
591
|
-
HTMLHandler
|
|
592
|
-
TextHandler
|
|
593
|
-
N3Handler
|
|
594
|
-
JsonLdHandler
|
|
413
|
+
const defaultHandlers = {
|
|
414
|
+
RDFXMLHandler,
|
|
415
|
+
XHTMLHandler,
|
|
416
|
+
XMLHandler,
|
|
417
|
+
HTMLHandler,
|
|
418
|
+
TextHandler,
|
|
419
|
+
N3Handler,
|
|
420
|
+
JsonLdHandler
|
|
595
421
|
};
|
|
596
|
-
|
|
597
422
|
function isXHTML(responseText) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
423
|
+
const docTypeStart = responseText.indexOf('<!DOCTYPE html');
|
|
424
|
+
const docTypeEnd = responseText.indexOf('>');
|
|
601
425
|
if (docTypeStart === -1 || docTypeEnd === -1 || docTypeStart > docTypeEnd) {
|
|
602
426
|
return false;
|
|
603
427
|
}
|
|
604
|
-
|
|
605
428
|
return responseText.substr(docTypeStart, docTypeEnd - docTypeStart).indexOf('XHTML') !== -1;
|
|
606
429
|
}
|
|
607
|
-
|
|
608
430
|
function isXML(responseText) {
|
|
609
|
-
|
|
431
|
+
const match = responseText.match(/\s*<\?xml\s+version\s*=[^<>]+\?>/);
|
|
610
432
|
return !!match;
|
|
611
433
|
}
|
|
612
|
-
|
|
613
434
|
function isXMLNS(responseText) {
|
|
614
|
-
|
|
435
|
+
const match = responseText.match(/[^(<html)]*<html\s+[^<]*xmlns=['"]http:\/\/www.w3.org\/1999\/xhtml["'][^<]*>/);
|
|
615
436
|
return !!match;
|
|
616
437
|
}
|
|
617
|
-
|
|
618
438
|
/** Fetcher
|
|
619
439
|
*
|
|
620
440
|
* The Fetcher object is a helper object for a quadstore
|
|
@@ -623,7 +443,7 @@ function isXMLNS(responseText) {
|
|
|
623
443
|
* figuring how to parse them. It will also refresh, remove, the data
|
|
624
444
|
* and put back the data to the web.
|
|
625
445
|
*/
|
|
626
|
-
|
|
446
|
+
class Fetcher {
|
|
627
447
|
/** Denoting this session */
|
|
628
448
|
|
|
629
449
|
/**
|
|
@@ -647,14 +467,13 @@ var Fetcher = /*#__PURE__*/function () {
|
|
|
647
467
|
/** fetchCallbacks[uri].push(callback) */
|
|
648
468
|
|
|
649
469
|
/** Keep track of explicit 404s -> we can overwrite etc */
|
|
470
|
+
|
|
650
471
|
// TODO: Document this
|
|
651
472
|
|
|
652
473
|
/** Methods added by calling Util.callbackify in the constructor*/
|
|
653
|
-
function Fetcher(store) {
|
|
654
|
-
var _this = this;
|
|
655
474
|
|
|
656
|
-
|
|
657
|
-
|
|
475
|
+
constructor(store) {
|
|
476
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
658
477
|
(0, _defineProperty2.default)(this, "store", void 0);
|
|
659
478
|
(0, _defineProperty2.default)(this, "timeout", void 0);
|
|
660
479
|
(0, _defineProperty2.default)(this, "_fetch", void 0);
|
|
@@ -672,17 +491,15 @@ var Fetcher = /*#__PURE__*/function () {
|
|
|
672
491
|
(0, _defineProperty2.default)(this, "fireCallbacks", void 0);
|
|
673
492
|
this.store = store || new _store.default();
|
|
674
493
|
this.ns = getNS(this.store.rdfFactory);
|
|
675
|
-
this.timeout = options.timeout || 30000;
|
|
494
|
+
this.timeout = options.timeout || 30000;
|
|
676
495
|
|
|
496
|
+
// solidFetcher is deprecated
|
|
677
497
|
this._fetch = options.fetch || typeof global !== 'undefined' && (global.solidFetcher || global.solidFetch) || typeof window !== 'undefined' && (window.solidFetcher || window.solidFetch) || _crossFetch.default;
|
|
678
|
-
|
|
679
498
|
if (!this._fetch) {
|
|
680
499
|
throw new Error('No _fetch function available for Fetcher');
|
|
681
500
|
}
|
|
682
|
-
|
|
683
501
|
this.appNode = this.store.rdfFactory.blankNode();
|
|
684
502
|
this.store.fetcher = this; // Bi-linked
|
|
685
|
-
|
|
686
503
|
this.requested = {};
|
|
687
504
|
this.timeouts = {};
|
|
688
505
|
this.redirectedTo = {};
|
|
@@ -698,258 +515,279 @@ var Fetcher = /*#__PURE__*/function () {
|
|
|
698
515
|
'*/*': {
|
|
699
516
|
'q': 0.1
|
|
700
517
|
} // Must allow access to random content
|
|
518
|
+
};
|
|
701
519
|
|
|
702
|
-
|
|
520
|
+
// Util.callbackify(this, ['request', 'recv', 'headers', 'load', 'fail',
|
|
703
521
|
// 'refresh', 'retract', 'done'])
|
|
704
522
|
// In switching to fetch(), 'recv', 'headers' and 'load' do not make sense
|
|
705
|
-
|
|
706
523
|
Util.callbackify(this, ['request', 'fail', 'refresh', 'retract', 'done']);
|
|
707
|
-
Object.keys(options.handlers || defaultHandlers).map(
|
|
708
|
-
return _this.addHandler(defaultHandlers[key]);
|
|
709
|
-
});
|
|
524
|
+
Object.keys(options.handlers || defaultHandlers).map(key => this.addHandler(defaultHandlers[key]));
|
|
710
525
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
* Promise-based load function
|
|
717
|
-
*
|
|
718
|
-
* Loads a web resource or resources into the store.
|
|
719
|
-
*
|
|
720
|
-
* A resource may be given as NamedNode object, or as a plain URI.
|
|
721
|
-
* an array of resources will be given, in which they will be fetched in parallel.
|
|
722
|
-
* By default, the HTTP headers are recorded also, in the same store, in a separate graph.
|
|
723
|
-
* This allows code like editable() for example to test things about the resource.
|
|
724
|
-
*
|
|
725
|
-
* @param uri {Array<RDFlibNamedNode>|Array<string>|RDFlibNamedNode|string}
|
|
726
|
-
*
|
|
727
|
-
* @param [options={}] {Object}
|
|
728
|
-
*
|
|
729
|
-
* @param [options.fetch] {Function}
|
|
730
|
-
*
|
|
731
|
-
* @param [options.referringTerm] {RDFlibNamedNode} Referring term, the resource which
|
|
732
|
-
* referred to this (for tracking bad links)
|
|
733
|
-
*
|
|
734
|
-
* @param [options.contentType] {string} Provided content type (for writes)
|
|
735
|
-
*
|
|
736
|
-
* @param [options.forceContentType] {string} Override the incoming header to
|
|
737
|
-
* force the data to be treated as this content-type (for reads)
|
|
738
|
-
*
|
|
739
|
-
* @param [options.force] {boolean} Load the data even if loaded before.
|
|
740
|
-
* Also sets the `Cache-Control:` header to `no-cache`
|
|
741
|
-
*
|
|
742
|
-
* @param [options.baseURI=docuri] {Node|string} Original uri to preserve
|
|
743
|
-
* through proxying etc (`xhr.original`).
|
|
744
|
-
*
|
|
745
|
-
* @param [options.proxyUsed] {boolean} Whether this request is a retry via
|
|
746
|
-
* a proxy (generally done from an error handler)
|
|
747
|
-
*
|
|
748
|
-
* @param [options.withCredentials] {boolean} flag for XHR/CORS etc
|
|
749
|
-
*
|
|
750
|
-
* @param [options.clearPreviousData] {boolean} Before we parse new data,
|
|
751
|
-
* clear old, but only on status 200 responses
|
|
752
|
-
*
|
|
753
|
-
* @param [options.noMeta] {boolean} Prevents the addition of various metadata
|
|
754
|
-
* triples (about the fetch request) to the store
|
|
755
|
-
*
|
|
756
|
-
* @param [options.noRDFa] {boolean}
|
|
757
|
-
*
|
|
758
|
-
* @returns {Promise<Result>}
|
|
759
|
-
*/
|
|
760
|
-
function load(uri) {
|
|
761
|
-
var _this2 = this;
|
|
762
|
-
|
|
763
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
764
|
-
options = Object.assign({}, options); // Take a copy as we add stuff to the options!!
|
|
765
|
-
|
|
766
|
-
if (uri instanceof Array) {
|
|
767
|
-
return Promise.all(uri.map(function (x) {
|
|
768
|
-
return _this2.load(x, Object.assign({}, options));
|
|
769
|
-
}));
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
var uriIn = uri;
|
|
773
|
-
var docuri = (0, _termValue.termValue)(uriIn);
|
|
774
|
-
docuri = docuri.split('#')[0];
|
|
775
|
-
options = this.initFetchOptions(docuri, options);
|
|
776
|
-
var initialisedOptions = this.initFetchOptions(docuri, options);
|
|
777
|
-
return this.pendingFetchPromise(docuri, initialisedOptions.baseURI, initialisedOptions);
|
|
526
|
+
static crossSiteProxy(uri) {
|
|
527
|
+
if (Fetcher.crossSiteProxyTemplate) {
|
|
528
|
+
return Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri));
|
|
529
|
+
} else {
|
|
530
|
+
return undefined;
|
|
778
531
|
}
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
532
|
+
}
|
|
533
|
+
static offlineOverride(uri) {
|
|
534
|
+
// Map the URI to a localhost proxy if we are running on localhost
|
|
535
|
+
// This is used for working offline, e.g. on planes.
|
|
536
|
+
// Is the script itself is running in localhost, then access all
|
|
537
|
+
// data in a localhost mirror.
|
|
538
|
+
// Do not remove without checking with TimBL
|
|
539
|
+
let requestedURI = uri;
|
|
540
|
+
var UI;
|
|
541
|
+
if (typeof window !== 'undefined' && window.panes && (UI = window.panes.UI) && UI.preferences && UI.preferences.get('offlineModeUsingLocalhost')) {
|
|
542
|
+
if (requestedURI.slice(0, 7) === 'http://' && requestedURI.slice(7, 17) !== 'localhost/') {
|
|
543
|
+
requestedURI = 'http://localhost/' + requestedURI.slice(7);
|
|
544
|
+
_log.default.warn('Localhost kludge for offline use: actually getting <' + requestedURI + '>');
|
|
788
545
|
} else {
|
|
789
|
-
|
|
790
|
-
this.fetchQueue[originalUri] = pendingPromise; // Clean up the queued promise after a time, if it's resolved
|
|
791
|
-
|
|
792
|
-
this.cleanupFetchRequest(originalUri, undefined, this.timeout);
|
|
546
|
+
// log.warn("Localhost kludge NOT USED <" + requestedURI + ">")
|
|
793
547
|
}
|
|
548
|
+
} else {
|
|
549
|
+
// log.warn("Localhost kludge OFF offline use: actually getting <" +
|
|
550
|
+
// requestedURI + ">")
|
|
551
|
+
}
|
|
552
|
+
return requestedURI;
|
|
553
|
+
}
|
|
554
|
+
static proxyIfNecessary(uri) {
|
|
555
|
+
var UI;
|
|
556
|
+
if (typeof window !== 'undefined' && window.panes && (UI = window.panes.UI) && UI.isExtension) {
|
|
557
|
+
return uri;
|
|
558
|
+
} // Extension does not need proxy
|
|
794
559
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
560
|
+
if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.localSiteMap) {
|
|
561
|
+
// nested dictionaries of URI parts from origin down
|
|
562
|
+
let hostpath = uri.split('/').slice(2); // the bit after the //
|
|
798
563
|
|
|
799
|
-
|
|
564
|
+
const lookup = (parts, index) => {
|
|
565
|
+
let z = index[parts.shift()];
|
|
566
|
+
if (!z) {
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
569
|
+
if (typeof z === 'string') {
|
|
570
|
+
return z + parts.join('/');
|
|
800
571
|
}
|
|
572
|
+
if (!parts) {
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
return lookup(parts, z);
|
|
576
|
+
};
|
|
577
|
+
const y = lookup(hostpath, $SolidTestEnvironment.localSiteMap);
|
|
578
|
+
if (y) {
|
|
579
|
+
return y;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
801
582
|
|
|
802
|
-
|
|
803
|
-
|
|
583
|
+
// browser does 2014 on as https browser script not trusted
|
|
584
|
+
// If the web app origin is https: then the mixed content rules
|
|
585
|
+
// prevent it loading insecure http: stuff so we need proxy.
|
|
586
|
+
if (Fetcher.crossSiteProxyTemplate && typeof document !== 'undefined' && document.location && ('' + document.location).slice(0, 6) === 'https:' &&
|
|
587
|
+
// origin is secure
|
|
588
|
+
uri.slice(0, 5) === 'http:') {
|
|
589
|
+
// requested data is not
|
|
590
|
+
return Fetcher.crossSiteProxyTemplate.replace('{uri}', encodeURIComponent(uri));
|
|
804
591
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
*/
|
|
592
|
+
return uri;
|
|
593
|
+
}
|
|
808
594
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
595
|
+
/**
|
|
596
|
+
* Tests whether the uri's protocol is supported by the Fetcher.
|
|
597
|
+
* @param uri
|
|
598
|
+
*/
|
|
599
|
+
static unsupportedProtocol(uri) {
|
|
600
|
+
let pcol = Uri.protocol(uri);
|
|
601
|
+
return pcol === 'tel' || pcol === 'mailto' || pcol === 'urn';
|
|
602
|
+
}
|
|
813
603
|
|
|
814
|
-
|
|
815
|
-
|
|
604
|
+
/** Decide on credentials using old XXHR api or new fetch() one
|
|
605
|
+
* @param requestedURI
|
|
606
|
+
* @param options
|
|
607
|
+
*/
|
|
608
|
+
static setCredentials(requestedURI) {
|
|
609
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
610
|
+
// 2014 CORS problem:
|
|
611
|
+
// XMLHttpRequest cannot load http://www.w3.org/People/Berners-Lee/card.
|
|
612
|
+
// A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin'
|
|
613
|
+
// header when the credentials flag is true.
|
|
614
|
+
// @ Many ontology files under http: and need CORS wildcard ->
|
|
615
|
+
// can't have credentials
|
|
616
|
+
if (options.credentials === undefined) {
|
|
617
|
+
// Caller using new fetch convention
|
|
618
|
+
if (options.withCredentials !== undefined) {
|
|
619
|
+
// XHR style is what Fetcher specified before
|
|
620
|
+
options.credentials = options.withCredentials ? 'include' : 'omit';
|
|
621
|
+
} else {
|
|
622
|
+
options.credentials = 'include'; // default is to be logged on
|
|
816
623
|
}
|
|
817
|
-
|
|
818
|
-
this.timeouts[originalUri] = (this.timeouts[originalUri] || []).concat(setTimeout(function () {
|
|
819
|
-
if (!_this4.isPending(originalUri)) {
|
|
820
|
-
delete _this4.fetchQueue[originalUri];
|
|
821
|
-
}
|
|
822
|
-
}, timeout));
|
|
823
624
|
}
|
|
824
|
-
}
|
|
825
|
-
key: "initFetchOptions",
|
|
826
|
-
value: function initFetchOptions(uri, options) {
|
|
827
|
-
var kb = this.store;
|
|
828
|
-
var isGet = !options.method || options.method.toUpperCase() === 'GET';
|
|
829
|
-
|
|
830
|
-
if (!isGet) {
|
|
831
|
-
options.force = true;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
options.resource = kb.rdfFactory.namedNode(uri); // This might be proxified
|
|
835
|
-
|
|
836
|
-
options.baseURI = options.baseURI || uri; // Preserve though proxying etc
|
|
837
|
-
|
|
838
|
-
options.original = kb.rdfFactory.namedNode(options.baseURI);
|
|
839
|
-
options.req = kb.bnode();
|
|
840
|
-
options.headers = options.headers || new _crossFetch.Headers();
|
|
841
|
-
|
|
842
|
-
if (options.contentType) {
|
|
843
|
-
// @ts-ignore
|
|
844
|
-
options.headers['content-type'] = options.contentType;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
if (options.force) {
|
|
848
|
-
options.cache = 'no-cache';
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
var acceptString = this.acceptString(); // @ts-ignore
|
|
852
|
-
|
|
853
|
-
options.headers['accept'] = acceptString;
|
|
854
|
-
var requestedURI = Fetcher.offlineOverride(uri);
|
|
855
|
-
options.requestedURI = requestedURI;
|
|
856
|
-
Fetcher.setCredentials(requestedURI, options);
|
|
857
|
-
var actualProxyURI = Fetcher.proxyIfNecessary(requestedURI);
|
|
858
|
-
|
|
859
|
-
if (requestedURI !== actualProxyURI) {
|
|
860
|
-
options.proxyUsed = true;
|
|
861
|
-
}
|
|
625
|
+
}
|
|
862
626
|
|
|
863
|
-
|
|
864
|
-
|
|
627
|
+
/**
|
|
628
|
+
* Promise-based load function
|
|
629
|
+
*
|
|
630
|
+
* Loads a web resource or resources into the store.
|
|
631
|
+
*
|
|
632
|
+
* A resource may be given as NamedNode object, or as a plain URI.
|
|
633
|
+
* an array of resources will be given, in which they will be fetched in parallel.
|
|
634
|
+
* By default, the HTTP headers are recorded also, in the same store, in a separate graph.
|
|
635
|
+
* This allows code like editable() for example to test things about the resource.
|
|
636
|
+
*
|
|
637
|
+
* @param uri {Array<RDFlibNamedNode>|Array<string>|RDFlibNamedNode|string}
|
|
638
|
+
*
|
|
639
|
+
* @param [options={}] {Object}
|
|
640
|
+
*
|
|
641
|
+
* @param [options.fetch] {Function}
|
|
642
|
+
*
|
|
643
|
+
* @param [options.referringTerm] {RDFlibNamedNode} Referring term, the resource which
|
|
644
|
+
* referred to this (for tracking bad links)
|
|
645
|
+
*
|
|
646
|
+
* @param [options.contentType] {string} Provided content type (for writes)
|
|
647
|
+
*
|
|
648
|
+
* @param [options.forceContentType] {string} Override the incoming header to
|
|
649
|
+
* force the data to be treated as this content-type (for reads)
|
|
650
|
+
*
|
|
651
|
+
* @param [options.force] {boolean} Load the data even if loaded before.
|
|
652
|
+
* Also sets the `Cache-Control:` header to `no-cache`
|
|
653
|
+
*
|
|
654
|
+
* @param [options.baseURI=docuri] {Node|string} Original uri to preserve
|
|
655
|
+
* through proxying etc (`xhr.original`).
|
|
656
|
+
*
|
|
657
|
+
* @param [options.proxyUsed] {boolean} Whether this request is a retry via
|
|
658
|
+
* a proxy (generally done from an error handler)
|
|
659
|
+
*
|
|
660
|
+
* @param [options.withCredentials] {boolean} flag for XHR/CORS etc
|
|
661
|
+
*
|
|
662
|
+
* @param [options.clearPreviousData] {boolean} Before we parse new data,
|
|
663
|
+
* clear old, but only on status 200 responses
|
|
664
|
+
*
|
|
665
|
+
* @param [options.noMeta] {boolean} Prevents the addition of various metadata
|
|
666
|
+
* triples (about the fetch request) to the store
|
|
667
|
+
*
|
|
668
|
+
* @param [options.noRDFa] {boolean}
|
|
669
|
+
*
|
|
670
|
+
* @returns {Promise<Result>}
|
|
671
|
+
*/
|
|
672
|
+
load(uri) {
|
|
673
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
674
|
+
options = Object.assign({}, options); // Take a copy as we add stuff to the options!!
|
|
675
|
+
if (uri instanceof Array) {
|
|
676
|
+
return Promise.all(uri.map(x => {
|
|
677
|
+
return this.load(x, Object.assign({}, options));
|
|
678
|
+
}));
|
|
865
679
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
680
|
+
const uriIn = uri;
|
|
681
|
+
let docuri = (0, _termValue.termValue)(uriIn);
|
|
682
|
+
docuri = docuri.split('#')[0];
|
|
683
|
+
options = this.initFetchOptions(docuri, options);
|
|
684
|
+
const initialisedOptions = this.initFetchOptions(docuri, options);
|
|
685
|
+
return this.pendingFetchPromise(docuri, initialisedOptions.baseURI, initialisedOptions);
|
|
686
|
+
}
|
|
687
|
+
async pendingFetchPromise(uri, originalUri, options) {
|
|
688
|
+
let pendingPromise;
|
|
689
|
+
|
|
690
|
+
// Check to see if some request is already dealing with this uri
|
|
691
|
+
if (!options.force && (await this.fetchQueue[originalUri])) {
|
|
692
|
+
pendingPromise = this.fetchQueue[originalUri];
|
|
693
|
+
} else {
|
|
694
|
+
pendingPromise = Promise.race([this.setRequestTimeout(uri, options), this.fetchUri(uri, options)]);
|
|
695
|
+
this.fetchQueue[originalUri] = pendingPromise;
|
|
696
|
+
|
|
697
|
+
// Clean up the queued promise after a time, if it's resolved
|
|
698
|
+
this.cleanupFetchRequest(originalUri, undefined, this.timeout);
|
|
699
|
+
}
|
|
700
|
+
return pendingPromise.then(x => {
|
|
701
|
+
if (uri in this.timeouts) {
|
|
702
|
+
this.timeouts[uri].forEach(clearTimeout);
|
|
703
|
+
delete this.timeouts[uri];
|
|
886
704
|
}
|
|
705
|
+
return x;
|
|
706
|
+
});
|
|
707
|
+
}
|
|
887
708
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
}));
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
if (state === 'failed' && this.requested[docuri] === 404) {
|
|
902
|
-
// Remember nonexistence
|
|
903
|
-
var _message = 'Previously failed: ' + this.requested[docuri]; // @ts-ignore This is not a valid response object
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
var dummyResponse = {
|
|
907
|
-
url: docuri,
|
|
908
|
-
// This does not comply to Fetch spec, it can be a string value in rdflib
|
|
909
|
-
status: this.requested[docuri],
|
|
910
|
-
statusText: _message,
|
|
911
|
-
responseText: _message,
|
|
912
|
-
headers: new _crossFetch.Headers(),
|
|
913
|
-
// Headers() ???
|
|
914
|
-
ok: false,
|
|
915
|
-
body: null,
|
|
916
|
-
bodyUsed: false,
|
|
917
|
-
size: 0,
|
|
918
|
-
timeout: 0
|
|
919
|
-
};
|
|
920
|
-
return this.failFetch(options, _message, this.requested[docuri], dummyResponse);
|
|
921
|
-
}
|
|
922
|
-
} else {
|
|
923
|
-
// options.force == true
|
|
924
|
-
delete this.nonexistent[docuri];
|
|
709
|
+
/**
|
|
710
|
+
* @param _options - DEPRECATED
|
|
711
|
+
*/
|
|
712
|
+
cleanupFetchRequest(originalUri, _options, timeout) {
|
|
713
|
+
if (_options !== undefined) {
|
|
714
|
+
console.warn("_options is deprecated");
|
|
715
|
+
}
|
|
716
|
+
this.timeouts[originalUri] = (this.timeouts[originalUri] || []).concat(setTimeout(() => {
|
|
717
|
+
if (!this.isPending(originalUri)) {
|
|
718
|
+
delete this.fetchQueue[originalUri];
|
|
925
719
|
}
|
|
720
|
+
}, timeout));
|
|
721
|
+
}
|
|
722
|
+
initFetchOptions(uri, options) {
|
|
723
|
+
let kb = this.store;
|
|
724
|
+
let isGet = !options.method || options.method.toUpperCase() === 'GET';
|
|
725
|
+
if (!isGet) {
|
|
726
|
+
options.force = true;
|
|
727
|
+
}
|
|
728
|
+
options.resource = kb.rdfFactory.namedNode(uri); // This might be proxified
|
|
729
|
+
options.baseURI = options.baseURI || uri; // Preserve though proxying etc
|
|
730
|
+
options.original = kb.rdfFactory.namedNode(options.baseURI);
|
|
731
|
+
options.req = kb.bnode();
|
|
732
|
+
options.headers = options.headers || new _crossFetch.Headers();
|
|
733
|
+
if (options.contentType) {
|
|
734
|
+
// @ts-ignore
|
|
735
|
+
options.headers['content-type'] = options.contentType;
|
|
736
|
+
}
|
|
737
|
+
if (options.force) {
|
|
738
|
+
options.cache = 'no-cache';
|
|
739
|
+
}
|
|
740
|
+
let acceptString = this.acceptString();
|
|
741
|
+
// @ts-ignore
|
|
742
|
+
options.headers['accept'] = acceptString;
|
|
743
|
+
let requestedURI = Fetcher.offlineOverride(uri);
|
|
744
|
+
options.requestedURI = requestedURI;
|
|
745
|
+
Fetcher.setCredentials(requestedURI, options);
|
|
746
|
+
let actualProxyURI = Fetcher.proxyIfNecessary(requestedURI);
|
|
747
|
+
if (requestedURI !== actualProxyURI) {
|
|
748
|
+
options.proxyUsed = true;
|
|
749
|
+
}
|
|
750
|
+
options.actualProxyURI = actualProxyURI;
|
|
751
|
+
return options;
|
|
752
|
+
}
|
|
926
753
|
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
754
|
+
/**
|
|
755
|
+
* (The promise chain ends in either a `failFetch()` or a `doneFetch()`)
|
|
756
|
+
*
|
|
757
|
+
* @param docuri {string}
|
|
758
|
+
* @param options {Object}
|
|
759
|
+
*
|
|
760
|
+
* @returns {Promise<Object>} fetch() result or an { error, status } object
|
|
761
|
+
*/
|
|
762
|
+
fetchUri(docuri, options) {
|
|
763
|
+
if (!docuri) {
|
|
764
|
+
return Promise.reject(new Error('Cannot fetch an empty uri'));
|
|
765
|
+
}
|
|
766
|
+
if (Fetcher.unsupportedProtocol(docuri)) {
|
|
767
|
+
return this.failFetch(options, 'fetcher: Unsupported protocol', 'unsupported_protocol');
|
|
768
|
+
}
|
|
769
|
+
let state = this.getState(docuri);
|
|
770
|
+
if (!options.force) {
|
|
771
|
+
if (state === 'fetched') {
|
|
772
|
+
// URI already fetched and added to store
|
|
773
|
+
return Promise.resolve(
|
|
774
|
+
// @ts-ignore This is not a valid response object
|
|
775
|
+
this.doneFetch(options, {
|
|
776
|
+
status: 200,
|
|
777
|
+
ok: true,
|
|
778
|
+
statusText: 'Already loaded into quadstore.'
|
|
779
|
+
}));
|
|
932
780
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
return _this5.handleResponse(response, docuri, options);
|
|
944
|
-
}, function (error) {
|
|
945
|
-
// @@ handleError?
|
|
946
|
-
// @ts-ignore Invalid response object
|
|
947
|
-
var dummyResponse = {
|
|
948
|
-
url: actualProxyURI,
|
|
949
|
-
status: 999,
|
|
950
|
-
// @@ what number/string should fetch failures report?
|
|
951
|
-
statusText: (error.name || 'network failure') + ': ' + (error.errno || error.code || error.type),
|
|
952
|
-
responseText: error.message,
|
|
781
|
+
if (state === 'failed' && this.requested[docuri] === 404) {
|
|
782
|
+
// Remember nonexistence
|
|
783
|
+
let message = 'Previously failed: ' + this.requested[docuri];
|
|
784
|
+
// @ts-ignore This is not a valid response object
|
|
785
|
+
let dummyResponse = {
|
|
786
|
+
url: docuri,
|
|
787
|
+
// This does not comply to Fetch spec, it can be a string value in rdflib
|
|
788
|
+
status: this.requested[docuri],
|
|
789
|
+
statusText: message,
|
|
790
|
+
responseText: message,
|
|
953
791
|
headers: new _crossFetch.Headers(),
|
|
954
792
|
// Headers() ???
|
|
955
793
|
ok: false,
|
|
@@ -958,1197 +796,886 @@ var Fetcher = /*#__PURE__*/function () {
|
|
|
958
796
|
size: 0,
|
|
959
797
|
timeout: 0
|
|
960
798
|
};
|
|
961
|
-
|
|
962
|
-
return _this5.handleError(dummyResponse, docuri, options); // possible credentials retry
|
|
963
|
-
// return this.failFetch(options, 'fetch failed: ' + error, 999, dummyResponse) // Fake status code: fetch exception
|
|
964
|
-
// handleError expects a response so we fake some important bits.
|
|
965
|
-
|
|
966
|
-
/*
|
|
967
|
-
this.handleError(, docuri, options)
|
|
968
|
-
*/
|
|
969
|
-
});
|
|
970
|
-
}
|
|
971
|
-
/**
|
|
972
|
-
* Asks for a doc to be loaded if necessary then calls back
|
|
973
|
-
*
|
|
974
|
-
* Calling methods:
|
|
975
|
-
* nowOrWhenFetched (uri, userCallback)
|
|
976
|
-
* nowOrWhenFetched (uri, options, userCallback)
|
|
977
|
-
* nowOrWhenFetched (uri, referringTerm, userCallback, options) <-- old
|
|
978
|
-
* nowOrWhenFetched (uri, referringTerm, userCallback) <-- old
|
|
979
|
-
*
|
|
980
|
-
* Options include:
|
|
981
|
-
* referringTerm The document in which this link was found.
|
|
982
|
-
* this is valuable when finding the source of bad URIs
|
|
983
|
-
* force boolean. Never mind whether you have tried before,
|
|
984
|
-
* load this from scratch.
|
|
985
|
-
* forceContentType Override the incoming header to force the data to be
|
|
986
|
-
* treated as this content-type.
|
|
987
|
-
*
|
|
988
|
-
* Callback function takes:
|
|
989
|
-
*
|
|
990
|
-
* ok True if the fetch worked, and got a 200 response.
|
|
991
|
-
* False if any error happened
|
|
992
|
-
*
|
|
993
|
-
* errmessage Text error message if not OK.
|
|
994
|
-
*
|
|
995
|
-
* response The fetch Response object (was: XHR) if there was was one
|
|
996
|
-
* includes response.status as the HTTP status if any.
|
|
997
|
-
*/
|
|
998
|
-
|
|
999
|
-
}, {
|
|
1000
|
-
key: "nowOrWhenFetched",
|
|
1001
|
-
value: function nowOrWhenFetched(uriIn, p2, userCallback) {
|
|
1002
|
-
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
1003
|
-
var uri = (0, _termValue.termValue)(uriIn);
|
|
1004
|
-
|
|
1005
|
-
if (typeof p2 === 'function') {
|
|
1006
|
-
// nowOrWhenFetched (uri, userCallback)
|
|
1007
|
-
userCallback = p2;
|
|
1008
|
-
} else if (typeof p2 === 'undefined') {// original calling signature
|
|
1009
|
-
// referringTerm = undefined
|
|
1010
|
-
} else if ((0, _terms.isNamedNode)(p2)) {
|
|
1011
|
-
// referringTerm = p2
|
|
1012
|
-
options.referringTerm = p2;
|
|
1013
|
-
} else {
|
|
1014
|
-
// nowOrWhenFetched (uri, options, userCallback)
|
|
1015
|
-
options = p2;
|
|
799
|
+
return this.failFetch(options, message, this.requested[docuri], dummyResponse);
|
|
1016
800
|
}
|
|
801
|
+
} else {
|
|
802
|
+
// options.force == true
|
|
803
|
+
delete this.nonexistent[docuri];
|
|
804
|
+
}
|
|
805
|
+
this.fireCallbacks('request', [docuri]);
|
|
806
|
+
this.requested[docuri] = true; // mark this uri as 'requested'
|
|
807
|
+
|
|
808
|
+
if (!options.noMeta) {
|
|
809
|
+
this.saveRequestMetadata(docuri, options);
|
|
810
|
+
}
|
|
811
|
+
let {
|
|
812
|
+
actualProxyURI
|
|
813
|
+
} = options;
|
|
814
|
+
|
|
815
|
+
// Map might get mistakenly added into headers
|
|
816
|
+
// error TS2339: Property 'map' does not exist on type 'Headers'.
|
|
817
|
+
/* let map
|
|
818
|
+
if (options.headers && map in options.headers) {
|
|
819
|
+
delete options.headers.map
|
|
820
|
+
} */
|
|
821
|
+
|
|
822
|
+
return this._fetch(actualProxyURI, options).then(response => this.handleResponse(response, docuri, options), error => {
|
|
823
|
+
// @@ handleError?
|
|
824
|
+
// @ts-ignore Invalid response object
|
|
825
|
+
let dummyResponse = {
|
|
826
|
+
url: actualProxyURI,
|
|
827
|
+
status: 999,
|
|
828
|
+
// @@ what number/string should fetch failures report?
|
|
829
|
+
statusText: (error.name || 'network failure') + ': ' + (error.errno || error.code || error.type),
|
|
830
|
+
responseText: error.message,
|
|
831
|
+
headers: new _crossFetch.Headers(),
|
|
832
|
+
// Headers() ???
|
|
833
|
+
ok: false,
|
|
834
|
+
body: null,
|
|
835
|
+
bodyUsed: false,
|
|
836
|
+
size: 0,
|
|
837
|
+
timeout: 0
|
|
838
|
+
};
|
|
839
|
+
console.log('Fetcher: <' + actualProxyURI + '> Non-HTTP fetch exception: ' + error);
|
|
840
|
+
return this.handleError(dummyResponse, docuri, options); // possible credentials retry
|
|
841
|
+
// return this.failFetch(options, 'fetch failed: ' + error, 999, dummyResponse) // Fake status code: fetch exception
|
|
1017
842
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
843
|
+
// handleError expects a response so we fake some important bits.
|
|
844
|
+
/*
|
|
845
|
+
this.handleError(, docuri, options)
|
|
846
|
+
*/
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Asks for a doc to be loaded if necessary then calls back
|
|
852
|
+
*
|
|
853
|
+
* Calling methods:
|
|
854
|
+
* nowOrWhenFetched (uri, userCallback)
|
|
855
|
+
* nowOrWhenFetched (uri, options, userCallback)
|
|
856
|
+
* nowOrWhenFetched (uri, referringTerm, userCallback, options) <-- old
|
|
857
|
+
* nowOrWhenFetched (uri, referringTerm, userCallback) <-- old
|
|
858
|
+
*
|
|
859
|
+
* Options include:
|
|
860
|
+
* referringTerm The document in which this link was found.
|
|
861
|
+
* this is valuable when finding the source of bad URIs
|
|
862
|
+
* force boolean. Never mind whether you have tried before,
|
|
863
|
+
* load this from scratch.
|
|
864
|
+
* forceContentType Override the incoming header to force the data to be
|
|
865
|
+
* treated as this content-type.
|
|
866
|
+
*
|
|
867
|
+
* Callback function takes:
|
|
868
|
+
*
|
|
869
|
+
* ok True if the fetch worked, and got a 200 response.
|
|
870
|
+
* False if any error happened
|
|
871
|
+
*
|
|
872
|
+
* errmessage Text error message if not OK.
|
|
873
|
+
*
|
|
874
|
+
* response The fetch Response object (was: XHR) if there was was one
|
|
875
|
+
* includes response.status as the HTTP status if any.
|
|
876
|
+
*/
|
|
877
|
+
nowOrWhenFetched(uriIn, p2, userCallback) {
|
|
878
|
+
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
879
|
+
const uri = (0, _termValue.termValue)(uriIn);
|
|
880
|
+
if (typeof p2 === 'function') {
|
|
881
|
+
// nowOrWhenFetched (uri, userCallback)
|
|
882
|
+
userCallback = p2;
|
|
883
|
+
} else if (typeof p2 === 'undefined') {// original calling signature
|
|
884
|
+
// referringTerm = undefined
|
|
885
|
+
} else if ((0, _terms.isNamedNode)(p2)) {
|
|
886
|
+
// referringTerm = p2
|
|
887
|
+
options.referringTerm = p2;
|
|
888
|
+
} else {
|
|
889
|
+
// nowOrWhenFetched (uri, options, userCallback)
|
|
890
|
+
options = p2;
|
|
891
|
+
}
|
|
892
|
+
this.load(uri, options).then(fetchResponse => {
|
|
893
|
+
if (userCallback) {
|
|
894
|
+
if (fetchResponse) {
|
|
895
|
+
if (fetchResponse.ok) {
|
|
896
|
+
userCallback(true, 'OK', fetchResponse);
|
|
1034
897
|
} else {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
}, function (err) {
|
|
1041
|
-
var message = err.message || err.statusText;
|
|
1042
|
-
message = 'Failed to load <' + uri + '> ' + message;
|
|
1043
|
-
console.log(message);
|
|
898
|
+
// console.log('@@@ fetcher.js Should not take this path !!!!!!!!!!!!')
|
|
899
|
+
let oops = 'HTTP error: Status ' + fetchResponse.status + ' (' + fetchResponse.statusText + ')';
|
|
900
|
+
if (fetchResponse.responseText) {
|
|
901
|
+
oops += ' ' + fetchResponse.responseText; // not in 404, dns error, nock failure
|
|
902
|
+
}
|
|
1044
903
|
|
|
1045
|
-
|
|
1046
|
-
|
|
904
|
+
console.log(oops + ' fetching ' + uri);
|
|
905
|
+
userCallback(false, oops, fetchResponse);
|
|
906
|
+
}
|
|
907
|
+
} else {
|
|
908
|
+
let oops = '@@ nowOrWhenFetched: no response object!';
|
|
909
|
+
console.log(oops);
|
|
910
|
+
userCallback(false, oops);
|
|
1047
911
|
}
|
|
912
|
+
}
|
|
913
|
+
}, function (err) {
|
|
914
|
+
var message = err.message || err.statusText;
|
|
915
|
+
message = 'Failed to load <' + uri + '> ' + message;
|
|
916
|
+
console.log(message);
|
|
917
|
+
if (err.response && err.response.status) {
|
|
918
|
+
message += ' status: ' + err.response.status;
|
|
919
|
+
}
|
|
920
|
+
userCallback(false, message, err.response);
|
|
921
|
+
});
|
|
922
|
+
}
|
|
1048
923
|
|
|
1049
|
-
|
|
1050
|
-
|
|
924
|
+
/**
|
|
925
|
+
* Records a status message (as a literal node) by appending it to the
|
|
926
|
+
* request's metadata status collection.
|
|
927
|
+
*
|
|
928
|
+
*/
|
|
929
|
+
addStatus(req, statusMessage) {
|
|
930
|
+
// <Debug about="parsePerformance">
|
|
931
|
+
let now = new Date();
|
|
932
|
+
statusMessage = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '.' + now.getMilliseconds() + '] ' + statusMessage;
|
|
933
|
+
// </Debug>
|
|
934
|
+
let kb = this.store;
|
|
935
|
+
const statusNode = kb.the(req, this.ns.link('status'));
|
|
936
|
+
if ((0, _terms.isCollection)(statusNode)) {
|
|
937
|
+
statusNode.append(kb.rdfFactory.literal(statusMessage));
|
|
938
|
+
} else {
|
|
939
|
+
_log.default.warn('web.js: No list to add to: ' + statusNode + ',' + statusMessage);
|
|
1051
940
|
}
|
|
1052
|
-
|
|
1053
|
-
* Records a status message (as a literal node) by appending it to the
|
|
1054
|
-
* request's metadata status collection.
|
|
1055
|
-
*
|
|
1056
|
-
*/
|
|
1057
|
-
|
|
1058
|
-
}, {
|
|
1059
|
-
key: "addStatus",
|
|
1060
|
-
value: function addStatus(req, statusMessage) {
|
|
1061
|
-
// <Debug about="parsePerformance">
|
|
1062
|
-
var now = new Date();
|
|
1063
|
-
statusMessage = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '.' + now.getMilliseconds() + '] ' + statusMessage; // </Debug>
|
|
1064
|
-
|
|
1065
|
-
var kb = this.store;
|
|
1066
|
-
var statusNode = kb.the(req, this.ns.link('status'));
|
|
941
|
+
}
|
|
1067
942
|
|
|
1068
|
-
|
|
1069
|
-
|
|
943
|
+
/**
|
|
944
|
+
* Records errors in the system on failure:
|
|
945
|
+
*
|
|
946
|
+
* - Adds an entry to the request status collection
|
|
947
|
+
* - Adds an error triple with the fail message to the metadata
|
|
948
|
+
* - Fires the 'fail' callback
|
|
949
|
+
* - Rejects with an error result object, which has a response object if any
|
|
950
|
+
*/
|
|
951
|
+
failFetch(options, errorMessage, statusCode, response) {
|
|
952
|
+
this.addStatus(options.req, errorMessage);
|
|
953
|
+
if (!options.noMeta) {
|
|
954
|
+
this.store.add(options.original, this.ns.link('error'), this.store.rdfFactory.literal(errorMessage));
|
|
955
|
+
}
|
|
956
|
+
let meth = (options.method || 'GET').toUpperCase();
|
|
957
|
+
let isGet = meth === 'GET' || meth === 'HEAD';
|
|
958
|
+
if (isGet) {
|
|
959
|
+
// only cache the status code on GET or HEAD
|
|
960
|
+
if (!options.resource.equals(options.original)) {
|
|
961
|
+
// console.log('@@ Recording failure ' + meth + ' original ' + options.original +option '( as ' + options.resource + ') : ' + statusCode)
|
|
1070
962
|
} else {
|
|
1071
|
-
|
|
963
|
+
// console.log('@@ Recording ' + meth + ' failure for ' + options.original + ': ' + statusCode)
|
|
1072
964
|
}
|
|
965
|
+
this.requested[Uri.docpart(options.original.value)] = statusCode;
|
|
966
|
+
this.fireCallbacks('fail', [options.original.value, errorMessage]);
|
|
1073
967
|
}
|
|
1074
|
-
|
|
1075
|
-
* Records errors in the system on failure:
|
|
1076
|
-
*
|
|
1077
|
-
* - Adds an entry to the request status collection
|
|
1078
|
-
* - Adds an error triple with the fail message to the metadata
|
|
1079
|
-
* - Fires the 'fail' callback
|
|
1080
|
-
* - Rejects with an error result object, which has a response object if any
|
|
1081
|
-
*/
|
|
1082
|
-
|
|
1083
|
-
}, {
|
|
1084
|
-
key: "failFetch",
|
|
1085
|
-
value: function failFetch(options, errorMessage, statusCode, response) {
|
|
1086
|
-
this.addStatus(options.req, errorMessage);
|
|
1087
|
-
|
|
1088
|
-
if (!options.noMeta) {
|
|
1089
|
-
this.store.add(options.original, this.ns.link('error'), this.store.rdfFactory.literal(errorMessage));
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
var meth = (options.method || 'GET').toUpperCase();
|
|
1093
|
-
var isGet = meth === 'GET' || meth === 'HEAD';
|
|
968
|
+
var err = new Error('Fetcher: ' + errorMessage);
|
|
1094
969
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
this.requested[Uri.docpart(options.original.value)] = statusCode;
|
|
1102
|
-
this.fireCallbacks('fail', [options.original.value, errorMessage]);
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
var err = new Error('Fetcher: ' + errorMessage); // err.ok = false // Is taken as a response, will work too @@ phase out?
|
|
1106
|
-
|
|
1107
|
-
err.status = statusCode;
|
|
1108
|
-
err.statusText = errorMessage;
|
|
1109
|
-
err.response = response;
|
|
1110
|
-
return Promise.reject(err);
|
|
1111
|
-
} // in the why part of the quad distinguish between HTML and HTTP header
|
|
1112
|
-
// Reverse is set iif the link was rev= as opposed to rel=
|
|
1113
|
-
|
|
1114
|
-
}, {
|
|
1115
|
-
key: "linkData",
|
|
1116
|
-
value: function linkData(originalUri, rel, uri, why, reverse) {
|
|
1117
|
-
if (!uri) return;
|
|
1118
|
-
var kb = this.store;
|
|
1119
|
-
var predicate; // See http://www.w3.org/TR/powder-dr/#httplink for describedby 2008-12-10
|
|
1120
|
-
|
|
1121
|
-
var obj = kb.rdfFactory.namedNode(Uri.join(uri, originalUri.value));
|
|
1122
|
-
|
|
1123
|
-
if (rel === 'alternate' || rel === 'seeAlso' || rel === 'meta' || rel === 'describedby') {
|
|
1124
|
-
if (obj.value === originalUri.value) {
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
predicate = this.ns.rdfs('seeAlso');
|
|
1129
|
-
} else if (rel === 'type') {
|
|
1130
|
-
predicate = kb.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
|
|
1131
|
-
} else {
|
|
1132
|
-
// See https://www.iana.org/assignments/link-relations/link-relations.xml
|
|
1133
|
-
// Alas not yet in RDF yet for each predicate
|
|
1134
|
-
// encode space in e.g. rel="shortcut icon"
|
|
1135
|
-
predicate = kb.rdfFactory.namedNode(Uri.join(encodeURIComponent(rel), 'http://www.iana.org/assignments/link-relations/'));
|
|
1136
|
-
}
|
|
970
|
+
// err.ok = false // Is taken as a response, will work too @@ phase out?
|
|
971
|
+
err.status = statusCode;
|
|
972
|
+
err.statusText = errorMessage;
|
|
973
|
+
err.response = response;
|
|
974
|
+
return Promise.reject(err);
|
|
975
|
+
}
|
|
1137
976
|
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
977
|
+
// in the why part of the quad distinguish between HTML and HTTP header
|
|
978
|
+
// Reverse is set iif the link was rev= as opposed to rel=
|
|
979
|
+
linkData(originalUri, rel, uri, why, reverse) {
|
|
980
|
+
if (!uri) return;
|
|
981
|
+
let kb = this.store;
|
|
982
|
+
let predicate;
|
|
983
|
+
// See http://www.w3.org/TR/powder-dr/#httplink for describedby 2008-12-10
|
|
984
|
+
let obj = kb.rdfFactory.namedNode(Uri.join(uri, originalUri.value));
|
|
985
|
+
if (rel === 'alternate' || rel === 'seeAlso' || rel === 'meta' || rel === 'describedby') {
|
|
986
|
+
if (obj.value === originalUri.value) {
|
|
987
|
+
return;
|
|
1142
988
|
}
|
|
989
|
+
predicate = this.ns.rdfs('seeAlso');
|
|
990
|
+
} else if (rel === 'type') {
|
|
991
|
+
predicate = kb.rdfFactory.namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
|
|
992
|
+
} else {
|
|
993
|
+
// See https://www.iana.org/assignments/link-relations/link-relations.xml
|
|
994
|
+
// Alas not yet in RDF yet for each predicate
|
|
995
|
+
// encode space in e.g. rel="shortcut icon"
|
|
996
|
+
predicate = kb.rdfFactory.namedNode(Uri.join(encodeURIComponent(rel), 'http://www.iana.org/assignments/link-relations/'));
|
|
997
|
+
}
|
|
998
|
+
if (reverse) {
|
|
999
|
+
kb.add(obj, predicate, originalUri, why);
|
|
1000
|
+
} else {
|
|
1001
|
+
kb.add(originalUri, predicate, obj, why);
|
|
1143
1002
|
}
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
var rel = paramsplit[1].replace(/["']/g, ''); // '"
|
|
1174
|
-
|
|
1175
|
-
this.linkData(originalUri, rel, href, reqNode);
|
|
1176
|
-
}
|
|
1003
|
+
}
|
|
1004
|
+
parseLinkHeader(linkHeader, originalUri, reqNode) {
|
|
1005
|
+
if (!linkHeader) {
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// const linkexp = /<[^>]*>\s*(\s*;\s*[^()<>@,;:"/[\]?={} \t]+=(([^()<>@,;:"/[]?={} \t]+)|("[^"]*")))*(,|$)/g
|
|
1010
|
+
// const paramexp = /[^()<>@,;:"/[]?={} \t]+=(([^()<>@,;:"/[]?={} \t]+)|("[^"]*"))/g
|
|
1011
|
+
|
|
1012
|
+
// From https://www.dcode.fr/regular-expression-simplificator:
|
|
1013
|
+
// const linkexp = /<[^>]*>\s*(\s*;\s*[^()<>@,;:"/[\]?={} t]+=["]))*[,$]/g
|
|
1014
|
+
// const paramexp = /[^\\<>@,;:"\/\[\]?={} \t]+=["])/g
|
|
1015
|
+
// Original:
|
|
1016
|
+
const linkexp = /<[^>]*>\s*(\s*;\s*[^()<>@,;:"/[\]?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|$)/g;
|
|
1017
|
+
const paramexp = /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g;
|
|
1018
|
+
const matches = linkHeader.match(linkexp);
|
|
1019
|
+
if (matches == null) return;
|
|
1020
|
+
for (let i = 0; i < matches.length; i++) {
|
|
1021
|
+
let split = matches[i].split('>');
|
|
1022
|
+
let href = split[0].substring(1);
|
|
1023
|
+
let ps = split[1];
|
|
1024
|
+
let s = ps.match(paramexp);
|
|
1025
|
+
if (s == null) return;
|
|
1026
|
+
for (let j = 0; j < s.length; j++) {
|
|
1027
|
+
let p = s[j];
|
|
1028
|
+
let paramsplit = p.split('=');
|
|
1029
|
+
// var name = paramsplit[0]
|
|
1030
|
+
let rel = paramsplit[1].replace(/["']/g, ''); // '"
|
|
1031
|
+
this.linkData(originalUri, rel, href, reqNode);
|
|
1177
1032
|
}
|
|
1178
1033
|
}
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
response.req = options.req; // Set the request meta blank node
|
|
1034
|
+
}
|
|
1035
|
+
doneFetch(options, response) {
|
|
1036
|
+
this.addStatus(options.req, 'Done.');
|
|
1037
|
+
this.requested[options.original.value] = 'done';
|
|
1038
|
+
this.fireCallbacks('done', [options.original.value]);
|
|
1039
|
+
response.req = options.req; // Set the request meta blank node
|
|
1186
1040
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
/**
|
|
1190
|
-
* Note two nodes are now smushed
|
|
1191
|
-
* If only one was flagged as looked up, then the new node is looked up again,
|
|
1192
|
-
* which will make sure all the URIs are dereferenced
|
|
1193
|
-
*/
|
|
1041
|
+
return response;
|
|
1042
|
+
}
|
|
1194
1043
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
this.lookUpThing(was, now);
|
|
1206
|
-
}
|
|
1044
|
+
/**
|
|
1045
|
+
* Note two nodes are now smushed
|
|
1046
|
+
* If only one was flagged as looked up, then the new node is looked up again,
|
|
1047
|
+
* which will make sure all the URIs are dereferenced
|
|
1048
|
+
*/
|
|
1049
|
+
nowKnownAs(was, now) {
|
|
1050
|
+
if (this.lookedUp[was.value]) {
|
|
1051
|
+
// Transfer userCallback
|
|
1052
|
+
if (!this.lookedUp[now.value]) {
|
|
1053
|
+
this.lookUpThing(now, was);
|
|
1207
1054
|
}
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
*/
|
|
1212
|
-
|
|
1213
|
-
}, {
|
|
1214
|
-
key: "putBack",
|
|
1215
|
-
value: function putBack(uri) {
|
|
1216
|
-
var _this6 = this;
|
|
1217
|
-
|
|
1218
|
-
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1219
|
-
var uriSting = (0, _termValue.termValue)(uri);
|
|
1220
|
-
var doc = new _namedNode.default(uriSting).doc(); // strip off #
|
|
1221
|
-
|
|
1222
|
-
options.contentType = options["content-type"] || options["Content-Type"] || options.contentType || _types.TurtleContentType;
|
|
1223
|
-
|
|
1224
|
-
if (options.contentType === 'application/ld+json') {
|
|
1225
|
-
return new Promise(function (resolve, reject) {
|
|
1226
|
-
(0, _serialize.default)(doc, _this6.store, doc.uri, options.contentType, function (err, jsonString) {
|
|
1227
|
-
if (err) {
|
|
1228
|
-
reject(err);
|
|
1229
|
-
} else {
|
|
1230
|
-
// @ts-ignore
|
|
1231
|
-
options.data = jsonString;
|
|
1232
|
-
|
|
1233
|
-
_this6.webOperation('PUT', uri, options).then(function (res) {
|
|
1234
|
-
return resolve(res);
|
|
1235
|
-
}).catch(function (error) {
|
|
1236
|
-
return reject(error);
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
});
|
|
1240
|
-
});
|
|
1055
|
+
} else if (this.lookedUp[now.value]) {
|
|
1056
|
+
if (!this.lookedUp[was.value]) {
|
|
1057
|
+
this.lookUpThing(was, now);
|
|
1241
1058
|
}
|
|
1242
|
-
|
|
1243
|
-
options.data = (0, _serialize.default)(doc, this.store, doc.value, options.contentType);
|
|
1244
|
-
return this.webOperation('PUT', uriSting, options);
|
|
1245
1059
|
}
|
|
1246
|
-
}
|
|
1247
|
-
key: "webCopy",
|
|
1248
|
-
value: function webCopy(here, there, contentType) {
|
|
1249
|
-
var _this7 = this;
|
|
1060
|
+
}
|
|
1250
1061
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1062
|
+
/**
|
|
1063
|
+
* Writes back to the web what we have in the store for this uri
|
|
1064
|
+
*/
|
|
1065
|
+
putBack(uri) {
|
|
1066
|
+
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1067
|
+
const uriSting = (0, _termValue.termValue)(uri);
|
|
1068
|
+
let doc = new _namedNode.default(uriSting).doc(); // strip off #
|
|
1069
|
+
options.contentType = options["content-type"] || options["Content-Type"] || options.contentType || _types.TurtleContentType;
|
|
1070
|
+
if (options.contentType === 'application/ld+json') {
|
|
1071
|
+
return new Promise((resolve, reject) => {
|
|
1072
|
+
(0, _serialize.default)(doc, this.store, doc.uri, options.contentType, (err, jsonString) => {
|
|
1073
|
+
if (err) {
|
|
1074
|
+
reject(err);
|
|
1075
|
+
} else {
|
|
1076
|
+
// @ts-ignore
|
|
1077
|
+
options.data = jsonString;
|
|
1078
|
+
this.webOperation('PUT', uri, options).then(res => resolve(res)).catch(error => reject(error));
|
|
1079
|
+
}
|
|
1256
1080
|
});
|
|
1257
1081
|
});
|
|
1258
1082
|
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
return this.webOperation('
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
return response;
|
|
1083
|
+
options.data = (0, _serialize.default)(doc, this.store, doc.value, options.contentType);
|
|
1084
|
+
return this.webOperation('PUT', uriSting, options);
|
|
1085
|
+
}
|
|
1086
|
+
webCopy(here, there, contentType) {
|
|
1087
|
+
return this.webOperation('GET', here).then(result => {
|
|
1088
|
+
return this.webOperation('PUT',
|
|
1089
|
+
// change to binary from text
|
|
1090
|
+
there, {
|
|
1091
|
+
data: result.responseText,
|
|
1092
|
+
contentType
|
|
1271
1093
|
});
|
|
1272
|
-
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
var _createIfNotExists = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(doc) {
|
|
1283
|
-
var contentType,
|
|
1284
|
-
data,
|
|
1285
|
-
fetcher,
|
|
1286
|
-
response,
|
|
1287
|
-
_args = arguments;
|
|
1288
|
-
return _regenerator.default.wrap(function _callee$(_context) {
|
|
1289
|
-
while (1) {
|
|
1290
|
-
switch (_context.prev = _context.next) {
|
|
1291
|
-
case 0:
|
|
1292
|
-
contentType = _args.length > 1 && _args[1] !== undefined ? _args[1] : _types.TurtleContentType;
|
|
1293
|
-
data = _args.length > 2 && _args[2] !== undefined ? _args[2] : '';
|
|
1294
|
-
fetcher = this;
|
|
1295
|
-
_context.prev = 3;
|
|
1296
|
-
_context.next = 6;
|
|
1297
|
-
return fetcher.load(doc);
|
|
1298
|
-
|
|
1299
|
-
case 6:
|
|
1300
|
-
response = _context.sent;
|
|
1301
|
-
_context.next = 29;
|
|
1302
|
-
break;
|
|
1303
|
-
|
|
1304
|
-
case 9:
|
|
1305
|
-
_context.prev = 9;
|
|
1306
|
-
_context.t0 = _context["catch"](3);
|
|
1307
|
-
|
|
1308
|
-
if (!(_context.t0.response.status === 404)) {
|
|
1309
|
-
_context.next = 27;
|
|
1310
|
-
break;
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
console.log('createIfNotExists: doc does NOT exist, will create... ' + doc);
|
|
1314
|
-
_context.prev = 13;
|
|
1315
|
-
_context.next = 16;
|
|
1316
|
-
return fetcher.webOperation('PUT', doc.value, {
|
|
1317
|
-
data: data,
|
|
1318
|
-
contentType: contentType
|
|
1319
|
-
});
|
|
1320
|
-
|
|
1321
|
-
case 16:
|
|
1322
|
-
response = _context.sent;
|
|
1323
|
-
_context.next = 23;
|
|
1324
|
-
break;
|
|
1325
|
-
|
|
1326
|
-
case 19:
|
|
1327
|
-
_context.prev = 19;
|
|
1328
|
-
_context.t1 = _context["catch"](13);
|
|
1329
|
-
console.log('createIfNotExists doc FAILED: ' + doc + ': ' + _context.t1);
|
|
1330
|
-
throw _context.t1;
|
|
1331
|
-
|
|
1332
|
-
case 23:
|
|
1333
|
-
delete fetcher.requested[doc.value]; // delete cached 404 error
|
|
1334
|
-
// console.log('createIfNotExists doc created ok ' + doc)
|
|
1335
|
-
|
|
1336
|
-
return _context.abrupt("return", response);
|
|
1337
|
-
|
|
1338
|
-
case 27:
|
|
1339
|
-
console.log('createIfNotExists doc load error NOT 404: ' + doc + ': ' + _context.t0);
|
|
1340
|
-
throw _context.t0;
|
|
1341
|
-
|
|
1342
|
-
case 29:
|
|
1343
|
-
return _context.abrupt("return", response);
|
|
1344
|
-
|
|
1345
|
-
case 30:
|
|
1346
|
-
case "end":
|
|
1347
|
-
return _context.stop();
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
}, _callee, this, [[3, 9], [13, 19]]);
|
|
1351
|
-
}));
|
|
1352
|
-
|
|
1353
|
-
function createIfNotExists(_x) {
|
|
1354
|
-
return _createIfNotExists.apply(this, arguments);
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
return createIfNotExists;
|
|
1358
|
-
}()
|
|
1359
|
-
/**
|
|
1360
|
-
* @param parentURI URI of parent container
|
|
1361
|
-
* @param folderName - Optional folder name (slug)
|
|
1362
|
-
* @param data - Optional folder metadata
|
|
1363
|
-
*/
|
|
1364
|
-
|
|
1365
|
-
}, {
|
|
1366
|
-
key: "createContainer",
|
|
1367
|
-
value: function createContainer(parentURI, folderName, data) {
|
|
1368
|
-
var headers = {
|
|
1369
|
-
// Force the right mime type for containers
|
|
1370
|
-
'content-type': _types.TurtleContentType,
|
|
1371
|
-
'link': this.ns.ldp('BasicContainer') + '; rel="type"'
|
|
1372
|
-
};
|
|
1373
|
-
|
|
1374
|
-
if (folderName) {
|
|
1375
|
-
headers['slug'] = folderName;
|
|
1376
|
-
} // @ts-ignore These headers lack some of the required operators.
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
var options = {
|
|
1380
|
-
headers: headers
|
|
1381
|
-
};
|
|
1382
|
-
|
|
1383
|
-
if (data) {
|
|
1384
|
-
options.body = data;
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
return this.webOperation('POST', parentURI, options);
|
|
1388
|
-
}
|
|
1389
|
-
}, {
|
|
1390
|
-
key: "invalidateCache",
|
|
1391
|
-
value: function invalidateCache(iri) {
|
|
1392
|
-
var uri = (0, _termValue.termValue)(iri);
|
|
1393
|
-
var fetcher = this; // @ts-ignore
|
|
1394
|
-
|
|
1395
|
-
if (fetcher.fetchQueue && fetcher.fetchQueue[uri]) {
|
|
1396
|
-
console.log('Internal error - fetchQueue exists ' + uri);
|
|
1397
|
-
var promise = fetcher.fetchQueue[uri];
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
delete(uri, options) {
|
|
1097
|
+
return this.webOperation('DELETE', uri, options).then(response => {
|
|
1098
|
+
this.requested[uri] = 404;
|
|
1099
|
+
this.nonexistent[uri] = true;
|
|
1100
|
+
this.unload(this.store.rdfFactory.namedNode(uri));
|
|
1101
|
+
return response;
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1398
1104
|
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1105
|
+
/** Create an empty resource if it really does not exist
|
|
1106
|
+
* Be absolutely sure something does not exist before creating a new empty file
|
|
1107
|
+
* as otherwise existing could be deleted.
|
|
1108
|
+
* @param doc - The resource
|
|
1109
|
+
*/
|
|
1110
|
+
async createIfNotExists(doc) {
|
|
1111
|
+
let contentType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _types.TurtleContentType;
|
|
1112
|
+
let data = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
|
|
1113
|
+
const fetcher = this;
|
|
1114
|
+
try {
|
|
1115
|
+
var response = await fetcher.load(doc);
|
|
1116
|
+
} catch (err) {
|
|
1117
|
+
// @ts-ignore
|
|
1118
|
+
if (err.response.status === 404) {
|
|
1119
|
+
console.log('createIfNotExists: doc does NOT exist, will create... ' + doc);
|
|
1120
|
+
try {
|
|
1121
|
+
response = await fetcher.webOperation('PUT', doc.value, {
|
|
1122
|
+
data,
|
|
1123
|
+
contentType
|
|
1124
|
+
});
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
console.log('createIfNotExists doc FAILED: ' + doc + ': ' + err);
|
|
1127
|
+
throw err;
|
|
1405
1128
|
}
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
var msg = "Rdflib: fetcher: Destructive operation on <".concat(fetcher.requested[uri], "> file being fetched! ") + uri;
|
|
1410
|
-
console.error(msg); // alert(msg)
|
|
1129
|
+
delete fetcher.requested[doc.value]; // delete cached 404 error
|
|
1130
|
+
// console.log('createIfNotExists doc created ok ' + doc)
|
|
1131
|
+
return response;
|
|
1411
1132
|
} else {
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
delete fetcher.nonexistent[uri];
|
|
1133
|
+
console.log('createIfNotExists doc load error NOT 404: ' + doc + ': ' + err);
|
|
1134
|
+
throw err;
|
|
1415
1135
|
}
|
|
1416
1136
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
*
|
|
1421
|
-
* Returns promise of Response
|
|
1422
|
-
* If data is returned, copies it to response.responseText before returning
|
|
1423
|
-
*/
|
|
1424
|
-
|
|
1425
|
-
}, {
|
|
1426
|
-
key: "webOperation",
|
|
1427
|
-
value: function webOperation(method, uriIn) {
|
|
1428
|
-
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
1429
|
-
var uri = (0, _termValue.termValue)(uriIn);
|
|
1430
|
-
options.method = method;
|
|
1431
|
-
options.body = options.data || options.body;
|
|
1432
|
-
options.force = true;
|
|
1433
|
-
var fetcher = this;
|
|
1434
|
-
|
|
1435
|
-
if (options.body && !options.contentType) {
|
|
1436
|
-
throw new Error('Web operation sending data must have a defined contentType.');
|
|
1437
|
-
}
|
|
1137
|
+
// console.log('createIfNotExists: doc exists, all good: ' + doc)
|
|
1138
|
+
return response;
|
|
1139
|
+
}
|
|
1438
1140
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1141
|
+
/**
|
|
1142
|
+
* @param parentURI URI of parent container
|
|
1143
|
+
* @param folderName - Optional folder name (slug)
|
|
1144
|
+
* @param data - Optional folder metadata
|
|
1145
|
+
*/
|
|
1146
|
+
createContainer(parentURI, folderName, data) {
|
|
1147
|
+
let headers = {
|
|
1148
|
+
// Force the right mime type for containers
|
|
1149
|
+
'content-type': _types.TurtleContentType,
|
|
1150
|
+
'link': this.ns.ldp('BasicContainer') + '; rel="type"'
|
|
1151
|
+
};
|
|
1152
|
+
if (folderName) {
|
|
1153
|
+
headers['slug'] = folderName;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// @ts-ignore These headers lack some of the required operators.
|
|
1157
|
+
let options = {
|
|
1158
|
+
headers
|
|
1159
|
+
};
|
|
1160
|
+
if (data) {
|
|
1161
|
+
options.body = data;
|
|
1162
|
+
}
|
|
1163
|
+
return this.webOperation('POST', parentURI, options);
|
|
1164
|
+
}
|
|
1165
|
+
invalidateCache(iri) {
|
|
1166
|
+
const uri = (0, _termValue.termValue)(iri);
|
|
1167
|
+
const fetcher = this;
|
|
1168
|
+
// @ts-ignore
|
|
1169
|
+
if (fetcher.fetchQueue && fetcher.fetchQueue[uri]) {
|
|
1170
|
+
console.log('Internal error - fetchQueue exists ' + uri);
|
|
1171
|
+
var promise = fetcher.fetchQueue[uri];
|
|
1172
|
+
if (promise['PromiseStatus'] === 'resolved') {
|
|
1173
|
+
delete fetcher.fetchQueue[uri];
|
|
1174
|
+
} else {
|
|
1175
|
+
// pending
|
|
1176
|
+
delete fetcher.fetchQueue[uri];
|
|
1177
|
+
console.log('*** Fetcher: pending fetchQueue deleted ' + uri);
|
|
1442
1178
|
}
|
|
1179
|
+
}
|
|
1180
|
+
if (fetcher.requested[uri] && fetcher.requested[uri] !== 'done' && fetcher.requested[uri] !== 'failed' && fetcher.requested[uri] !== 404) {
|
|
1181
|
+
let msg = `Rdflib: fetcher: Destructive operation on <${fetcher.requested[uri]}> file being fetched! ` + uri;
|
|
1182
|
+
console.error(msg);
|
|
1183
|
+
// alert(msg)
|
|
1184
|
+
} else {
|
|
1185
|
+
delete fetcher.requested[uri]; // invalidate read cache -- @@ messes up logic if request in progress ??
|
|
1186
|
+
delete fetcher.nonexistent[uri];
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1443
1189
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1190
|
+
/**
|
|
1191
|
+
* A generic web operation, at the fetch() level.
|
|
1192
|
+
* does not involve the quad store.
|
|
1193
|
+
*
|
|
1194
|
+
* Returns promise of Response
|
|
1195
|
+
* If data is returned, copies it to response.responseText before returning
|
|
1196
|
+
*/
|
|
1197
|
+
webOperation(method, uriIn) {
|
|
1198
|
+
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
1199
|
+
const uri = (0, _termValue.termValue)(uriIn);
|
|
1200
|
+
options.method = method;
|
|
1201
|
+
options.body = options.data || options.body;
|
|
1202
|
+
options.force = true;
|
|
1203
|
+
const fetcher = this;
|
|
1204
|
+
if (options.body && !options.contentType) {
|
|
1205
|
+
throw new Error('Web operation sending data must have a defined contentType.');
|
|
1206
|
+
}
|
|
1207
|
+
if (options.contentType) {
|
|
1208
|
+
options.headers = options.headers || {};
|
|
1209
|
+
options.headers['content-type'] = options.contentType;
|
|
1210
|
+
}
|
|
1211
|
+
Fetcher.setCredentials(uri, options);
|
|
1212
|
+
return new Promise(function (resolve, reject) {
|
|
1213
|
+
fetcher._fetch(uri, options).then(response => {
|
|
1214
|
+
if (response.ok) {
|
|
1215
|
+
if (method === 'PUT' || method === 'PATCH' || method === 'POST' || method === 'DELETE') {
|
|
1216
|
+
fetcher.invalidateCache(uri);
|
|
1217
|
+
} // response.body with Chrome can't be relied on
|
|
1218
|
+
if (response.text) {
|
|
1219
|
+
// Was: response.body https://github.com/linkeddata/rdflib.js/issues/506
|
|
1220
|
+
response.text().then(data => {
|
|
1221
|
+
response.responseText = data;
|
|
1460
1222
|
resolve(response);
|
|
1461
|
-
}
|
|
1223
|
+
});
|
|
1462
1224
|
} else {
|
|
1463
|
-
|
|
1464
|
-
if (response.statusText) msg += ' (' + response.statusText + ')';
|
|
1465
|
-
msg += ' on ' + method + ' of <' + uri + '>';
|
|
1466
|
-
if (response.responseText) msg += ': ' + response.responseText;
|
|
1467
|
-
var e2 = new Error(msg);
|
|
1468
|
-
e2.response = response;
|
|
1469
|
-
reject(e2);
|
|
1225
|
+
resolve(response);
|
|
1470
1226
|
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
* @param rterm - the resource which referred to this
|
|
1484
|
-
* (for tracking bad links)
|
|
1485
|
-
*/
|
|
1486
|
-
|
|
1487
|
-
}, {
|
|
1488
|
-
key: "lookUpThing",
|
|
1489
|
-
value: function lookUpThing(term, rterm) {
|
|
1490
|
-
var _this9 = this;
|
|
1491
|
-
|
|
1492
|
-
var uris = this.store.uris(term); // Get all URIs
|
|
1493
|
-
|
|
1494
|
-
uris = uris.map(function (u) {
|
|
1495
|
-
return Uri.docpart(u);
|
|
1496
|
-
}); // Drop hash fragments
|
|
1497
|
-
|
|
1498
|
-
uris.forEach(function (u) {
|
|
1499
|
-
_this9.lookedUp[u] = true;
|
|
1500
|
-
}); // @ts-ignore Recursive type
|
|
1501
|
-
|
|
1502
|
-
return this.load(uris, {
|
|
1503
|
-
referringTerm: rterm
|
|
1227
|
+
} else {
|
|
1228
|
+
let msg = 'Web error: ' + response.status;
|
|
1229
|
+
if (response.statusText) msg += ' (' + response.statusText + ')';
|
|
1230
|
+
msg += ' on ' + method + ' of <' + uri + '>';
|
|
1231
|
+
if (response.responseText) msg += ': ' + response.responseText;
|
|
1232
|
+
let e2 = new Error(msg);
|
|
1233
|
+
e2.response = response;
|
|
1234
|
+
reject(e2);
|
|
1235
|
+
}
|
|
1236
|
+
}, err => {
|
|
1237
|
+
let msg = 'Fetch error for ' + method + ' of <' + uri + '>:' + err;
|
|
1238
|
+
reject(new Error(msg));
|
|
1504
1239
|
});
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
* Looks up response header.
|
|
1508
|
-
*
|
|
1509
|
-
* @returns {Array|undefined} a list of header values found in a stored HTTP
|
|
1510
|
-
* response, or [] if response was found but no header found,
|
|
1511
|
-
* or undefined if no response is available.
|
|
1512
|
-
* Looks for { [] link:requestedURI ?uri; link:response [ httph:header-name ?value ] }
|
|
1513
|
-
*/
|
|
1514
|
-
|
|
1515
|
-
}, {
|
|
1516
|
-
key: "getHeader",
|
|
1517
|
-
value: function getHeader(doc, header) {
|
|
1518
|
-
var kb = this.store; // look for the URI (AS A STRING NOT A NODE) for a stored request
|
|
1519
|
-
|
|
1520
|
-
var docuri = doc.value;
|
|
1521
|
-
var requests = kb.each(undefined, this.ns.link('requestedURI'), kb.rdfFactory.literal(docuri));
|
|
1522
|
-
|
|
1523
|
-
for (var r = 0; r < requests.length; r++) {
|
|
1524
|
-
var request = requests[r];
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1525
1242
|
|
|
1526
|
-
|
|
1527
|
-
|
|
1243
|
+
/**
|
|
1244
|
+
* Looks up something.
|
|
1245
|
+
* Looks up all the URIs a things has.
|
|
1246
|
+
*
|
|
1247
|
+
* @param term - canonical term for the thing whose URI is
|
|
1248
|
+
* to be dereferenced
|
|
1249
|
+
* @param rterm - the resource which referred to this
|
|
1250
|
+
* (for tracking bad links)
|
|
1251
|
+
*/
|
|
1252
|
+
lookUpThing(term, rterm) {
|
|
1253
|
+
let uris = this.store.uris(term); // Get all URIs
|
|
1254
|
+
uris = uris.map(u => Uri.docpart(u)); // Drop hash fragments
|
|
1528
1255
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1256
|
+
uris.forEach(u => {
|
|
1257
|
+
this.lookedUp[u] = true;
|
|
1258
|
+
});
|
|
1532
1259
|
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1260
|
+
// @ts-ignore Recursive type
|
|
1261
|
+
return this.load(uris, {
|
|
1262
|
+
referringTerm: rterm
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1538
1265
|
|
|
1539
|
-
|
|
1266
|
+
/**
|
|
1267
|
+
* Looks up response header.
|
|
1268
|
+
*
|
|
1269
|
+
* @returns {Array|undefined} a list of header values found in a stored HTTP
|
|
1270
|
+
* response, or [] if response was found but no header found,
|
|
1271
|
+
* or undefined if no response is available.
|
|
1272
|
+
* Looks for { [] link:requestedURI ?uri; link:response [ httph:header-name ?value ] }
|
|
1273
|
+
*/
|
|
1274
|
+
getHeader(doc, header) {
|
|
1275
|
+
const kb = this.store; // look for the URI (AS A STRING NOT A NODE) for a stored request
|
|
1276
|
+
const docuri = doc.value;
|
|
1277
|
+
const requests = kb.each(undefined, this.ns.link('requestedURI'), kb.rdfFactory.literal(docuri));
|
|
1278
|
+
for (let r = 0; r < requests.length; r++) {
|
|
1279
|
+
let request = requests[r];
|
|
1280
|
+
if (request !== undefined) {
|
|
1281
|
+
let response = kb.any(request, this.ns.link('response'));
|
|
1282
|
+
if (response !== undefined && kb.anyValue(response, this.ns.http('status')) && kb.anyValue(response, this.ns.http('status')).startsWith('2')) {
|
|
1283
|
+
// Only look at success returns - not 401 error messagess etc
|
|
1284
|
+
let results = kb.each(response, this.ns.httph(header.toLowerCase()));
|
|
1285
|
+
if (results.length) {
|
|
1286
|
+
return results.map(v => {
|
|
1287
|
+
return v.value;
|
|
1288
|
+
});
|
|
1540
1289
|
}
|
|
1290
|
+
return [];
|
|
1541
1291
|
}
|
|
1542
1292
|
}
|
|
1543
|
-
|
|
1544
|
-
return undefined;
|
|
1545
1293
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1294
|
+
return undefined;
|
|
1295
|
+
}
|
|
1296
|
+
saveRequestMetadata(docuri, options) {
|
|
1297
|
+
let req = options.req;
|
|
1298
|
+
let kb = this.store;
|
|
1299
|
+
let rterm = options.referringTerm;
|
|
1300
|
+
this.addStatus(options.req, 'Accept: ' + options.headers['accept']);
|
|
1301
|
+
if ((0, _terms.isNamedNode)(rterm)) {
|
|
1302
|
+
kb.add(kb.rdfFactory.namedNode(docuri), this.ns.link('requestedBy'), rterm, this.appNode);
|
|
1303
|
+
}
|
|
1304
|
+
if (options.original && options.original.value !== docuri) {
|
|
1305
|
+
kb.add(req, this.ns.link('orginalURI'), kb.rdfFactory.literal(options.original.value), this.appNode);
|
|
1306
|
+
}
|
|
1307
|
+
const now = new Date();
|
|
1308
|
+
const timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] ';
|
|
1309
|
+
kb.add(req, this.ns.rdfs('label'), kb.rdfFactory.literal(timeNow + ' Request for ' + docuri), this.appNode);
|
|
1310
|
+
// We store the docuri as a string, not as a node,
|
|
1311
|
+
// see https://github.com/linkeddata/rdflib.js/pull/427#pullrequestreview-447910061
|
|
1312
|
+
kb.add(req, this.ns.link('requestedURI'), kb.rdfFactory.literal(docuri), this.appNode);
|
|
1313
|
+
kb.add(req, this.ns.link('status'), kb.collection(), this.appNode);
|
|
1314
|
+
}
|
|
1315
|
+
saveResponseMetadata(response, options) {
|
|
1316
|
+
const kb = this.store;
|
|
1317
|
+
let responseNode = kb.bnode();
|
|
1318
|
+
kb.add(options.req, this.ns.link('response'), responseNode, responseNode);
|
|
1319
|
+
kb.add(responseNode, this.ns.http('status'), kb.rdfFactory.literal(response.status), responseNode);
|
|
1320
|
+
kb.add(responseNode, this.ns.http('statusText'), kb.rdfFactory.literal(response.statusText), responseNode);
|
|
1321
|
+
|
|
1322
|
+
// Save the response headers
|
|
1323
|
+
response.headers.forEach((value, header) => {
|
|
1324
|
+
kb.add(responseNode, this.ns.httph(header), this.store.rdfFactory.literal(value), responseNode);
|
|
1325
|
+
if (header === 'content-type') {
|
|
1326
|
+
kb.add(options.resource, this.ns.rdf('type'), kb.rdfFactory.namedNode(Util.mediaTypeClass(value).value), responseNode);
|
|
1556
1327
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1328
|
+
});
|
|
1329
|
+
return responseNode;
|
|
1330
|
+
}
|
|
1331
|
+
objectRefresh(term) {
|
|
1332
|
+
let uris = this.store.uris(term); // Get all URIs
|
|
1333
|
+
if (typeof uris !== 'undefined') {
|
|
1334
|
+
for (let i = 0; i < uris.length; i++) {
|
|
1335
|
+
this.refresh(this.store.rdfFactory.namedNode(Uri.docpart(uris[i])));
|
|
1336
|
+
// what about rterm?
|
|
1560
1337
|
}
|
|
1561
|
-
|
|
1562
|
-
var now = new Date();
|
|
1563
|
-
var timeNow = '[' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + '] ';
|
|
1564
|
-
kb.add(req, this.ns.rdfs('label'), kb.rdfFactory.literal(timeNow + ' Request for ' + docuri), this.appNode); // We store the docuri as a string, not as a node,
|
|
1565
|
-
// see https://github.com/linkeddata/rdflib.js/pull/427#pullrequestreview-447910061
|
|
1566
|
-
|
|
1567
|
-
kb.add(req, this.ns.link('requestedURI'), kb.rdfFactory.literal(docuri), this.appNode);
|
|
1568
|
-
kb.add(req, this.ns.link('status'), kb.collection(), this.appNode);
|
|
1569
1338
|
}
|
|
1570
|
-
}
|
|
1571
|
-
key: "saveResponseMetadata",
|
|
1572
|
-
value: function saveResponseMetadata(response, options) {
|
|
1573
|
-
var _this10 = this;
|
|
1574
|
-
|
|
1575
|
-
var kb = this.store;
|
|
1576
|
-
var responseNode = kb.bnode();
|
|
1577
|
-
kb.add(options.req, this.ns.link('response'), responseNode, responseNode);
|
|
1578
|
-
kb.add(responseNode, this.ns.http('status'), kb.rdfFactory.literal(response.status), responseNode);
|
|
1579
|
-
kb.add(responseNode, this.ns.http('statusText'), kb.rdfFactory.literal(response.statusText), responseNode); // Save the response headers
|
|
1339
|
+
}
|
|
1580
1340
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1341
|
+
/* refresh Reload data from a given document
|
|
1342
|
+
**
|
|
1343
|
+
** @param term - An RDF Named Node for the eodcument in question
|
|
1344
|
+
** @param userCallback - A function userCallback(ok, message, response)
|
|
1345
|
+
*/
|
|
1346
|
+
refresh(term, userCallback) {
|
|
1347
|
+
// sources_refresh
|
|
1348
|
+
this.fireCallbacks('refresh', arguments);
|
|
1349
|
+
this.nowOrWhenFetched(term, {
|
|
1350
|
+
force: true,
|
|
1351
|
+
clearPreviousData: true
|
|
1352
|
+
}, userCallback);
|
|
1353
|
+
}
|
|
1583
1354
|
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1355
|
+
/* refreshIfExpired Conditional refresh if Expired
|
|
1356
|
+
**
|
|
1357
|
+
** @param term - An RDF Named Node for the eodcument in question
|
|
1358
|
+
** @param userCallback - A function userCallback(ok, message, response)
|
|
1359
|
+
*/
|
|
1360
|
+
refreshIfExpired(term, userCallback) {
|
|
1361
|
+
let exp = this.getHeader(term, 'Expires');
|
|
1362
|
+
if (!exp || new Date(exp[0]).getTime() <= new Date().getTime()) {
|
|
1363
|
+
this.refresh(term, userCallback);
|
|
1364
|
+
} else {
|
|
1365
|
+
userCallback(true, 'Not expired', {});
|
|
1589
1366
|
}
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
for (var i = 0; i < uris.length; i++) {
|
|
1597
|
-
this.refresh(this.store.rdfFactory.namedNode(Uri.docpart(uris[i]))); // what about rterm?
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1367
|
+
}
|
|
1368
|
+
retract(term) {
|
|
1369
|
+
// sources_retract
|
|
1370
|
+
this.store.removeMany(undefined, undefined, undefined, term);
|
|
1371
|
+
if (term.value) {
|
|
1372
|
+
delete this.requested[Uri.docpart(term.value)];
|
|
1600
1373
|
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
this.
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
}, userCallback);
|
|
1616
|
-
}
|
|
1617
|
-
/* refreshIfExpired Conditional refresh if Expired
|
|
1618
|
-
**
|
|
1619
|
-
** @param term - An RDF Named Node for the eodcument in question
|
|
1620
|
-
** @param userCallback - A function userCallback(ok, message, response)
|
|
1621
|
-
*/
|
|
1622
|
-
|
|
1623
|
-
}, {
|
|
1624
|
-
key: "refreshIfExpired",
|
|
1625
|
-
value: function refreshIfExpired(term, userCallback) {
|
|
1626
|
-
var exp = this.getHeader(term, 'Expires');
|
|
1627
|
-
|
|
1628
|
-
if (!exp || new Date(exp[0]).getTime() <= new Date().getTime()) {
|
|
1629
|
-
this.refresh(term, userCallback);
|
|
1630
|
-
} else {
|
|
1631
|
-
userCallback(true, 'Not expired', {});
|
|
1632
|
-
}
|
|
1374
|
+
this.fireCallbacks('retract', arguments);
|
|
1375
|
+
}
|
|
1376
|
+
getState(docuri) {
|
|
1377
|
+
if (typeof this.requested[docuri] === 'undefined') {
|
|
1378
|
+
return 'unrequested';
|
|
1379
|
+
} else if (this.requested[docuri] === true) {
|
|
1380
|
+
return 'requested';
|
|
1381
|
+
} else if (this.requested[docuri] === 'done') {
|
|
1382
|
+
return 'fetched';
|
|
1383
|
+
} else if (this.requested[docuri] === 'redirected') {
|
|
1384
|
+
return this.getState(this.redirectedTo[docuri]);
|
|
1385
|
+
} else {
|
|
1386
|
+
// An non-200 HTTP error status
|
|
1387
|
+
return 'failed';
|
|
1633
1388
|
}
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1389
|
+
}
|
|
1390
|
+
isPending(docuri) {
|
|
1391
|
+
// sources_pending
|
|
1392
|
+
// doing anyStatementMatching is wasting time
|
|
1393
|
+
// if it's not pending: false -> flailed
|
|
1394
|
+
// 'done' -> done 'redirected' -> redirected
|
|
1395
|
+
return this.requested[docuri] === true;
|
|
1396
|
+
}
|
|
1397
|
+
unload(term) {
|
|
1398
|
+
this.store.removeDocument(term);
|
|
1399
|
+
delete this.requested[term.value]; // So it can be load2ed again
|
|
1400
|
+
}
|
|
1639
1401
|
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1402
|
+
addHandler(handler) {
|
|
1403
|
+
this.handlers.push(handler);
|
|
1404
|
+
handler.register(this);
|
|
1405
|
+
}
|
|
1406
|
+
retryNoCredentials(docuri, options) {
|
|
1407
|
+
console.log('Fetcher: CORS: RETRYING with NO CREDENTIALS for ' + options.resource);
|
|
1408
|
+
options.retriedWithNoCredentials = true; // protect against being called twice
|
|
1409
|
+
|
|
1410
|
+
delete this.requested[docuri]; // forget the original request happened
|
|
1411
|
+
delete this.fetchQueue[docuri];
|
|
1412
|
+
// Note: XHR property was withCredentials, but fetch property is just credentials
|
|
1413
|
+
let newOptions = Object.assign({}, options, {
|
|
1414
|
+
credentials: 'omit'
|
|
1415
|
+
});
|
|
1416
|
+
this.addStatus(options.req, 'Abort: Will retry with credentials SUPPRESSED to see if that helps');
|
|
1417
|
+
return this.load(docuri, newOptions);
|
|
1418
|
+
}
|
|
1643
1419
|
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
} else {
|
|
1658
|
-
// An non-200 HTTP error status
|
|
1659
|
-
return 'failed';
|
|
1660
|
-
}
|
|
1661
|
-
}
|
|
1662
|
-
}, {
|
|
1663
|
-
key: "isPending",
|
|
1664
|
-
value: function isPending(docuri) {
|
|
1665
|
-
// sources_pending
|
|
1666
|
-
// doing anyStatementMatching is wasting time
|
|
1667
|
-
// if it's not pending: false -> flailed
|
|
1668
|
-
// 'done' -> done 'redirected' -> redirected
|
|
1669
|
-
return this.requested[docuri] === true;
|
|
1670
|
-
}
|
|
1671
|
-
}, {
|
|
1672
|
-
key: "unload",
|
|
1673
|
-
value: function unload(term) {
|
|
1674
|
-
this.store.removeDocument(term);
|
|
1675
|
-
delete this.requested[term.value]; // So it can be load2ed again
|
|
1676
|
-
}
|
|
1677
|
-
}, {
|
|
1678
|
-
key: "addHandler",
|
|
1679
|
-
value: function addHandler(handler) {
|
|
1680
|
-
this.handlers.push(handler);
|
|
1681
|
-
handler.register(this);
|
|
1682
|
-
}
|
|
1683
|
-
}, {
|
|
1684
|
-
key: "retryNoCredentials",
|
|
1685
|
-
value: function retryNoCredentials(docuri, options) {
|
|
1686
|
-
console.log('Fetcher: CORS: RETRYING with NO CREDENTIALS for ' + options.resource);
|
|
1687
|
-
options.retriedWithNoCredentials = true; // protect against being called twice
|
|
1688
|
-
|
|
1689
|
-
delete this.requested[docuri]; // forget the original request happened
|
|
1690
|
-
|
|
1691
|
-
delete this.fetchQueue[docuri]; // Note: XHR property was withCredentials, but fetch property is just credentials
|
|
1692
|
-
|
|
1693
|
-
var newOptions = Object.assign({}, options, {
|
|
1694
|
-
credentials: 'omit'
|
|
1695
|
-
});
|
|
1696
|
-
this.addStatus(options.req, 'Abort: Will retry with credentials SUPPRESSED to see if that helps');
|
|
1697
|
-
return this.load(docuri, newOptions);
|
|
1698
|
-
}
|
|
1699
|
-
/**
|
|
1700
|
-
* Tests whether a request is being made to a cross-site URI (for purposes
|
|
1701
|
-
* of retrying with a proxy)
|
|
1702
|
-
*/
|
|
1420
|
+
/**
|
|
1421
|
+
* Tests whether a request is being made to a cross-site URI (for purposes
|
|
1422
|
+
* of retrying with a proxy)
|
|
1423
|
+
*/
|
|
1424
|
+
isCrossSite(uri) {
|
|
1425
|
+
// Mashup situation, not node etc
|
|
1426
|
+
if (typeof document === 'undefined' || !document.location) {
|
|
1427
|
+
return false;
|
|
1428
|
+
}
|
|
1429
|
+
const hostpart = Uri.hostpart;
|
|
1430
|
+
const here = '' + document.location;
|
|
1431
|
+
return (hostpart(here) && hostpart(uri) && hostpart(here)) !== hostpart(uri);
|
|
1432
|
+
}
|
|
1703
1433
|
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1434
|
+
/**
|
|
1435
|
+
* Called when there's a network error in fetch(), or a response
|
|
1436
|
+
* with status of 0.
|
|
1437
|
+
*/
|
|
1438
|
+
handleError(response, docuri, options) {
|
|
1439
|
+
if (this.isCrossSite(docuri)) {
|
|
1440
|
+
// Make sure we haven't retried already
|
|
1441
|
+
if (options.credentials && options.credentials === 'include' && !options.retriedWithNoCredentials) {
|
|
1442
|
+
return this.retryNoCredentials(docuri, options);
|
|
1710
1443
|
}
|
|
1711
1444
|
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
* Called when there's a network error in fetch(), or a response
|
|
1718
|
-
* with status of 0.
|
|
1719
|
-
*/
|
|
1720
|
-
|
|
1721
|
-
}, {
|
|
1722
|
-
key: "handleError",
|
|
1723
|
-
value: function handleError(response, docuri, options) {
|
|
1724
|
-
if (this.isCrossSite(docuri)) {
|
|
1725
|
-
// Make sure we haven't retried already
|
|
1726
|
-
if (options.credentials && options.credentials === 'include' && !options.retriedWithNoCredentials) {
|
|
1727
|
-
return this.retryNoCredentials(docuri, options);
|
|
1728
|
-
} // Now attempt retry via proxy
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
var proxyUri = Fetcher.crossSiteProxy(docuri);
|
|
1732
|
-
|
|
1733
|
-
if (proxyUri && !options.proxyUsed) {
|
|
1734
|
-
console.log('web: Direct failed so trying proxy ' + proxyUri);
|
|
1735
|
-
return this.redirectToProxy(proxyUri, options);
|
|
1736
|
-
}
|
|
1445
|
+
// Now attempt retry via proxy
|
|
1446
|
+
let proxyUri = Fetcher.crossSiteProxy(docuri);
|
|
1447
|
+
if (proxyUri && !options.proxyUsed) {
|
|
1448
|
+
console.log('web: Direct failed so trying proxy ' + proxyUri);
|
|
1449
|
+
return this.redirectToProxy(proxyUri, options);
|
|
1737
1450
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
if (response.responseText) {
|
|
1747
|
-
message += " ".concat(response.responseText);
|
|
1748
|
-
}
|
|
1749
|
-
} // This is either not a CORS error, or retries have been made
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
return this.failFetch(options, message, response.status || 998, response);
|
|
1753
|
-
} // deduce some things from the HTTP transaction
|
|
1754
|
-
|
|
1755
|
-
}, {
|
|
1756
|
-
key: "addType",
|
|
1757
|
-
value: function addType(rdfType, req, kb, locURI) {
|
|
1758
|
-
// add type to all redirected resources too
|
|
1759
|
-
var prev = req;
|
|
1760
|
-
|
|
1761
|
-
if (locURI) {
|
|
1762
|
-
var reqURI = kb.any(prev, this.ns.link('requestedURI'));
|
|
1763
|
-
|
|
1764
|
-
if (reqURI && reqURI.value !== locURI) {
|
|
1765
|
-
kb.add(kb.rdfFactory.namedNode(locURI), this.ns.rdf('type'), rdfType, this.appNode);
|
|
1766
|
-
}
|
|
1451
|
+
}
|
|
1452
|
+
var message;
|
|
1453
|
+
if (response instanceof Error) {
|
|
1454
|
+
message = 'Fetch error: ' + response.message;
|
|
1455
|
+
} else {
|
|
1456
|
+
message = response.statusText;
|
|
1457
|
+
if (response.responseText) {
|
|
1458
|
+
message += ` ${response.responseText}`;
|
|
1767
1459
|
}
|
|
1460
|
+
}
|
|
1768
1461
|
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
if (doc && doc.value) {
|
|
1773
|
-
kb.add(kb.rdfFactory.namedNode(doc.value), this.ns.rdf('type'), rdfType, this.appNode);
|
|
1774
|
-
} // convert Literal
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
prev = kb.any(undefined, kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/link#redirectedRequest'), prev);
|
|
1778
|
-
|
|
1779
|
-
if (!prev) {
|
|
1780
|
-
break;
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
var response = kb.any(prev, kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/link#response'));
|
|
1784
|
-
|
|
1785
|
-
if (!response) {
|
|
1786
|
-
break;
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
var redirection = kb.any(response, kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/http#status'));
|
|
1790
|
-
|
|
1791
|
-
if (!redirection) {
|
|
1792
|
-
break;
|
|
1793
|
-
} // @ts-ignore always true?
|
|
1794
|
-
|
|
1462
|
+
// This is either not a CORS error, or retries have been made
|
|
1463
|
+
return this.failFetch(options, message, response.status || 998, response);
|
|
1464
|
+
}
|
|
1795
1465
|
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1466
|
+
// deduce some things from the HTTP transaction
|
|
1467
|
+
addType(rdfType, req, kb, locURI) {
|
|
1468
|
+
// add type to all redirected resources too
|
|
1469
|
+
let prev = req;
|
|
1470
|
+
if (locURI) {
|
|
1471
|
+
var reqURI = kb.any(prev, this.ns.link('requestedURI'));
|
|
1472
|
+
if (reqURI && reqURI.value !== locURI) {
|
|
1473
|
+
kb.add(kb.rdfFactory.namedNode(locURI), this.ns.rdf('type'), rdfType, this.appNode);
|
|
1799
1474
|
}
|
|
1800
1475
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
var kb = this.store;
|
|
1811
|
-
var headers = response.headers;
|
|
1812
|
-
var reqNode = options.req;
|
|
1813
|
-
var responseNode = this.saveResponseMetadata(response, options);
|
|
1814
|
-
var contentType = this.normalizedContentType(options, headers) || '';
|
|
1815
|
-
var contentLocation = headers.get('content-location'); // this.fireCallbacks('recv', xhr.args)
|
|
1816
|
-
// this.fireCallbacks('headers', [{uri: docuri, headers: xhr.headers}])
|
|
1817
|
-
// Check for masked errors (CORS, etc)
|
|
1818
|
-
|
|
1819
|
-
if (response.status === 0) {
|
|
1820
|
-
console.log('Masked error - status 0 for ' + docuri);
|
|
1821
|
-
return this.handleError(response, docuri, options);
|
|
1476
|
+
for (;;) {
|
|
1477
|
+
const doc = kb.any(prev, this.ns.link('requestedURI'));
|
|
1478
|
+
if (doc && doc.value) {
|
|
1479
|
+
kb.add(kb.rdfFactory.namedNode(doc.value), this.ns.rdf('type'), rdfType, this.appNode);
|
|
1480
|
+
} // convert Literal
|
|
1481
|
+
prev = kb.any(undefined, kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/link#redirectedRequest'), prev);
|
|
1482
|
+
if (!prev) {
|
|
1483
|
+
break;
|
|
1822
1484
|
}
|
|
1823
|
-
|
|
1824
|
-
if (response
|
|
1825
|
-
|
|
1826
|
-
this.nonexistent[options.original.value] = true;
|
|
1827
|
-
this.nonexistent[docuri] = true;
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
|
-
return this.saveErrorResponse(response, responseNode).then(function () {
|
|
1831
|
-
var errorMessage = options.resource + ' ' + response.statusText;
|
|
1832
|
-
return _this11.failFetch(options, errorMessage, response.status, response);
|
|
1833
|
-
});
|
|
1485
|
+
var response = kb.any(prev, kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/link#response'));
|
|
1486
|
+
if (!response) {
|
|
1487
|
+
break;
|
|
1834
1488
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
if (contentLocation) {
|
|
1840
|
-
absContentLocation = Uri.join(contentLocation, docuri);
|
|
1841
|
-
|
|
1842
|
-
if (absContentLocation !== docuri) {
|
|
1843
|
-
diffLocation = absContentLocation;
|
|
1844
|
-
}
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
|
-
if (response.status === 200) {
|
|
1848
|
-
this.addType(this.ns.link('Document'), reqNode, kb, docuri);
|
|
1849
|
-
|
|
1850
|
-
if (diffLocation) {
|
|
1851
|
-
this.addType(this.ns.link('Document'), reqNode, kb, diffLocation);
|
|
1852
|
-
} // Before we parse new data clear old but only on 200
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
if (options.clearPreviousData) {
|
|
1856
|
-
kb.removeDocument(options.resource);
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
var isImage = contentType.includes('image/') || contentType.includes('application/pdf');
|
|
1860
|
-
|
|
1861
|
-
if (contentType && isImage) {
|
|
1862
|
-
this.addType(kb.rdfFactory.namedNode('http://purl.org/dc/terms/Image'), reqNode, kb, docuri);
|
|
1863
|
-
|
|
1864
|
-
if (diffLocation) {
|
|
1865
|
-
this.addType(kb.rdfFactory.namedNode('http://purl.org/dc/terms/Image'), reqNode, kb, diffLocation);
|
|
1866
|
-
}
|
|
1867
|
-
}
|
|
1868
|
-
} // If we have already got the thing at this location, abort
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
if (contentLocation) {
|
|
1872
|
-
if (!options.force && diffLocation && this.requested[absContentLocation] === 'done') {
|
|
1873
|
-
// we have already fetched this
|
|
1874
|
-
// should we smush too?
|
|
1875
|
-
// log.info("HTTP headers indicate we have already" + " retrieved " +
|
|
1876
|
-
// xhr.resource + " as " + absContentLocation + ". Aborting.")
|
|
1877
|
-
return this.doneFetch(options, response);
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
this.requested[absContentLocation] = true;
|
|
1489
|
+
var redirection = kb.any(response, kb.rdfFactory.namedNode('http://www.w3.org/2007/ont/http#status'));
|
|
1490
|
+
if (!redirection) {
|
|
1491
|
+
break;
|
|
1881
1492
|
}
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
if (!handler) {
|
|
1887
|
-
// Not a problem, we just don't extract data
|
|
1888
|
-
this.addStatus(reqNode, 'Fetch over. No data handled.');
|
|
1889
|
-
return this.doneFetch(options, response);
|
|
1493
|
+
// @ts-ignore always true?
|
|
1494
|
+
if (redirection !== '301' && redirection !== '302') {
|
|
1495
|
+
break;
|
|
1890
1496
|
}
|
|
1891
|
-
|
|
1892
|
-
return response.text() // @ts-ignore Types seem right
|
|
1893
|
-
.then(function (responseText) {
|
|
1894
|
-
response.responseText = responseText;
|
|
1895
|
-
return handler.parse(_this11, responseText, options, response);
|
|
1896
|
-
});
|
|
1897
1497
|
}
|
|
1898
|
-
}
|
|
1899
|
-
key: "saveErrorResponse",
|
|
1900
|
-
value: function saveErrorResponse(response, responseNode) {
|
|
1901
|
-
var _this12 = this;
|
|
1498
|
+
}
|
|
1902
1499
|
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1500
|
+
/**
|
|
1501
|
+
* Handle fetch() response
|
|
1502
|
+
*/
|
|
1503
|
+
handleResponse(response, docuri, options) {
|
|
1504
|
+
const kb = this.store;
|
|
1505
|
+
const headers = response.headers;
|
|
1506
|
+
const reqNode = options.req;
|
|
1507
|
+
const responseNode = this.saveResponseMetadata(response, options);
|
|
1508
|
+
const contentType = this.normalizedContentType(options, headers) || '';
|
|
1509
|
+
let contentLocation = headers.get('content-location');
|
|
1510
|
+
|
|
1511
|
+
// this.fireCallbacks('recv', xhr.args)
|
|
1512
|
+
// this.fireCallbacks('headers', [{uri: docuri, headers: xhr.headers}])
|
|
1513
|
+
|
|
1514
|
+
// Check for masked errors (CORS, etc)
|
|
1515
|
+
if (response.status === 0) {
|
|
1516
|
+
console.log('Masked error - status 0 for ' + docuri);
|
|
1517
|
+
return this.handleError(response, docuri, options);
|
|
1518
|
+
}
|
|
1519
|
+
if (response.status >= 400) {
|
|
1520
|
+
if (response.status === 404) {
|
|
1521
|
+
this.nonexistent[options.original.value] = true;
|
|
1522
|
+
this.nonexistent[docuri] = true;
|
|
1523
|
+
}
|
|
1524
|
+
return this.saveErrorResponse(response, responseNode).then(() => {
|
|
1525
|
+
let errorMessage = options.resource + ' ' + response.statusText;
|
|
1526
|
+
return this.failFetch(options, errorMessage, response.status, response);
|
|
1908
1527
|
});
|
|
1909
1528
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1529
|
+
var diffLocation = null;
|
|
1530
|
+
var absContentLocation = null;
|
|
1531
|
+
if (contentLocation) {
|
|
1532
|
+
absContentLocation = Uri.join(contentLocation, docuri);
|
|
1533
|
+
if (absContentLocation !== docuri) {
|
|
1534
|
+
diffLocation = absContentLocation;
|
|
1915
1535
|
}
|
|
1916
|
-
|
|
1917
|
-
var Handler = this.handlers.find(function (handler) {
|
|
1918
|
-
return contentType.match(handler.pattern);
|
|
1919
|
-
}); // @ts-ignore in practice all Handlers have constructors.
|
|
1920
|
-
|
|
1921
|
-
return Handler ? new Handler(response) : null;
|
|
1922
1536
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
}
|
|
1928
|
-
}, {
|
|
1929
|
-
key: "normalizedContentType",
|
|
1930
|
-
value: function normalizedContentType(options, headers) {
|
|
1931
|
-
if (options.forceContentType) {
|
|
1932
|
-
return options.forceContentType;
|
|
1537
|
+
if (response.status === 200) {
|
|
1538
|
+
this.addType(this.ns.link('Document'), reqNode, kb, docuri);
|
|
1539
|
+
if (diffLocation) {
|
|
1540
|
+
this.addType(this.ns.link('Document'), reqNode, kb, diffLocation);
|
|
1933
1541
|
}
|
|
1934
1542
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
var guess = this.guessContentType(options.resource.value);
|
|
1939
|
-
|
|
1940
|
-
if (guess) {
|
|
1941
|
-
return guess;
|
|
1942
|
-
}
|
|
1543
|
+
// Before we parse new data clear old but only on 200
|
|
1544
|
+
if (options.clearPreviousData) {
|
|
1545
|
+
kb.removeDocument(options.resource);
|
|
1943
1546
|
}
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
return contentType;
|
|
1952
|
-
}
|
|
1953
|
-
/**
|
|
1954
|
-
* Sends a new request to the specified uri. (Extracted from `onerrorFactory()`)
|
|
1955
|
-
*/
|
|
1956
|
-
|
|
1957
|
-
}, {
|
|
1958
|
-
key: "redirectToProxy",
|
|
1959
|
-
value: function redirectToProxy(newURI, options) {
|
|
1960
|
-
var _this13 = this;
|
|
1961
|
-
|
|
1962
|
-
this.addStatus(options.req, 'BLOCKED -> Cross-site Proxy to <' + newURI + '>');
|
|
1963
|
-
options.proxyUsed = true;
|
|
1964
|
-
var kb = this.store;
|
|
1965
|
-
var oldReq = options.req; // request metadata blank node
|
|
1966
|
-
|
|
1967
|
-
if (!options.noMeta) {
|
|
1968
|
-
kb.add(oldReq, this.ns.link('redirectedTo'), kb.rdfFactory.namedNode(newURI), oldReq);
|
|
1969
|
-
this.addStatus(oldReq, 'redirected to new request'); // why
|
|
1970
|
-
}
|
|
1971
|
-
|
|
1972
|
-
this.requested[options.resource.value] = 'redirected';
|
|
1973
|
-
this.redirectedTo[options.resource.value] = newURI;
|
|
1974
|
-
var newOptions = Object.assign({}, options);
|
|
1975
|
-
newOptions.baseURI = options.resource.value;
|
|
1976
|
-
return this.fetchUri(newURI, newOptions).then(function (response) {
|
|
1977
|
-
if (!newOptions.noMeta) {
|
|
1978
|
-
kb.add(oldReq, _this13.ns.link('redirectedRequest'), newOptions.req, _this13.appNode);
|
|
1547
|
+
let isImage = contentType.includes('image/') || contentType.includes('application/pdf');
|
|
1548
|
+
if (contentType && isImage) {
|
|
1549
|
+
this.addType(kb.rdfFactory.namedNode('http://purl.org/dc/terms/Image'), reqNode, kb, docuri);
|
|
1550
|
+
if (diffLocation) {
|
|
1551
|
+
this.addType(kb.rdfFactory.namedNode('http://purl.org/dc/terms/Image'), reqNode, kb, diffLocation);
|
|
1979
1552
|
}
|
|
1980
|
-
|
|
1981
|
-
return response;
|
|
1982
|
-
});
|
|
1983
|
-
}
|
|
1984
|
-
}, {
|
|
1985
|
-
key: "setRequestTimeout",
|
|
1986
|
-
value: function setRequestTimeout(uri, options) {
|
|
1987
|
-
var _this14 = this;
|
|
1988
|
-
|
|
1989
|
-
return new Promise(function (resolve) {
|
|
1990
|
-
_this14.timeouts[uri] = (_this14.timeouts[uri] || []).concat(setTimeout(function () {
|
|
1991
|
-
if (_this14.isPending(uri) && !options.retriedWithNoCredentials && !options.proxyUsed) {
|
|
1992
|
-
resolve(_this14.failFetch(options, "Request to ".concat(uri, " timed out"), 'timeout'));
|
|
1993
|
-
}
|
|
1994
|
-
}, _this14.timeout));
|
|
1995
|
-
});
|
|
1996
|
-
}
|
|
1997
|
-
}, {
|
|
1998
|
-
key: "addFetchCallback",
|
|
1999
|
-
value: function addFetchCallback(uri, callback) {
|
|
2000
|
-
if (!this.fetchCallbacks[uri]) {
|
|
2001
|
-
this.fetchCallbacks[uri] = [callback];
|
|
2002
|
-
} else {
|
|
2003
|
-
this.fetchCallbacks[uri].push(callback);
|
|
2004
1553
|
}
|
|
2005
1554
|
}
|
|
2006
|
-
}, {
|
|
2007
|
-
key: "acceptString",
|
|
2008
|
-
value: function acceptString() {
|
|
2009
|
-
var acceptstring = '';
|
|
2010
|
-
|
|
2011
|
-
for (var mediaType in this.mediatypes) {
|
|
2012
|
-
if (acceptstring !== '') {
|
|
2013
|
-
acceptstring += ', ';
|
|
2014
|
-
}
|
|
2015
|
-
|
|
2016
|
-
acceptstring += mediaType;
|
|
2017
|
-
|
|
2018
|
-
for (var property in this.mediatypes[mediaType]) {
|
|
2019
|
-
acceptstring += ';' + property + '=' + this.mediatypes[mediaType][property];
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
|
|
2023
|
-
return acceptstring;
|
|
2024
|
-
} // var updatesVia = new $rdf.UpdatesVia(this) // Subscribe to headers
|
|
2025
|
-
// @@@@@@@@ This is turned off because it causes a websocket to be set up for ANY fetch
|
|
2026
|
-
// whether we want to track it ot not. including ontologies loaed though the XSSproxy
|
|
2027
1555
|
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
1556
|
+
// If we have already got the thing at this location, abort
|
|
1557
|
+
if (contentLocation) {
|
|
1558
|
+
if (!options.force && diffLocation && this.requested[absContentLocation] === 'done') {
|
|
1559
|
+
// we have already fetched this
|
|
1560
|
+
// should we smush too?
|
|
1561
|
+
// log.info("HTTP headers indicate we have already" + " retrieved " +
|
|
1562
|
+
// xhr.resource + " as " + absContentLocation + ". Aborting.")
|
|
1563
|
+
return this.doneFetch(options, response);
|
|
2035
1564
|
}
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
//
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
1565
|
+
this.requested[absContentLocation] = true;
|
|
1566
|
+
}
|
|
1567
|
+
this.parseLinkHeader(headers.get('link'), options.original, reqNode);
|
|
1568
|
+
let handler = this.handlerForContentType(contentType, response);
|
|
1569
|
+
if (!handler) {
|
|
1570
|
+
// Not a problem, we just don't extract data
|
|
1571
|
+
this.addStatus(reqNode, 'Fetch over. No data handled.');
|
|
1572
|
+
return this.doneFetch(options, response);
|
|
1573
|
+
}
|
|
1574
|
+
return response.text()
|
|
1575
|
+
// @ts-ignore Types seem right
|
|
1576
|
+
.then(responseText => {
|
|
1577
|
+
response.responseText = responseText;
|
|
1578
|
+
return handler.parse(this, responseText, options, response);
|
|
1579
|
+
});
|
|
1580
|
+
}
|
|
1581
|
+
saveErrorResponse(response, responseNode) {
|
|
1582
|
+
let kb = this.store;
|
|
1583
|
+
return response.text().then(content => {
|
|
1584
|
+
if (content.length > 10) {
|
|
1585
|
+
kb.add(responseNode, this.ns.http('content'), kb.rdfFactory.literal(content), responseNode);
|
|
2057
1586
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
1587
|
+
});
|
|
1588
|
+
}
|
|
1589
|
+
handlerForContentType(contentType, response) {
|
|
1590
|
+
if (!contentType) {
|
|
1591
|
+
return null;
|
|
2060
1592
|
}
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
var UI;
|
|
2065
|
-
|
|
2066
|
-
if (typeof window !== 'undefined' && window.panes && (UI = window.panes.UI) && UI.isExtension) {
|
|
2067
|
-
return uri;
|
|
2068
|
-
} // Extension does not need proxy
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
if (typeof $SolidTestEnvironment !== 'undefined' && $SolidTestEnvironment.localSiteMap) {
|
|
2072
|
-
// nested dictionaries of URI parts from origin down
|
|
2073
|
-
var hostpath = uri.split('/').slice(2); // the bit after the //
|
|
2074
|
-
|
|
2075
|
-
var lookup = function lookup(parts, index) {
|
|
2076
|
-
var z = index[parts.shift()];
|
|
2077
|
-
|
|
2078
|
-
if (!z) {
|
|
2079
|
-
return null;
|
|
2080
|
-
}
|
|
2081
|
-
|
|
2082
|
-
if (typeof z === 'string') {
|
|
2083
|
-
return z + parts.join('/');
|
|
2084
|
-
}
|
|
2085
|
-
|
|
2086
|
-
if (!parts) {
|
|
2087
|
-
return null;
|
|
2088
|
-
}
|
|
2089
|
-
|
|
2090
|
-
return lookup(parts, z);
|
|
2091
|
-
};
|
|
2092
|
-
|
|
2093
|
-
var y = lookup(hostpath, $SolidTestEnvironment.localSiteMap);
|
|
2094
|
-
|
|
2095
|
-
if (y) {
|
|
2096
|
-
return y;
|
|
2097
|
-
}
|
|
2098
|
-
} // browser does 2014 on as https browser script not trusted
|
|
2099
|
-
// If the web app origin is https: then the mixed content rules
|
|
2100
|
-
// prevent it loading insecure http: stuff so we need proxy.
|
|
2101
|
-
|
|
1593
|
+
let Handler = this.handlers.find(handler => {
|
|
1594
|
+
return contentType.match(handler.pattern);
|
|
1595
|
+
});
|
|
2102
1596
|
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
1597
|
+
// @ts-ignore in practice all Handlers have constructors.
|
|
1598
|
+
return Handler ? new Handler(response) : null;
|
|
1599
|
+
}
|
|
1600
|
+
guessContentType(uri) {
|
|
1601
|
+
return CONTENT_TYPE_BY_EXT[uri.split('.').pop()];
|
|
1602
|
+
}
|
|
1603
|
+
normalizedContentType(options, headers) {
|
|
1604
|
+
if (options.forceContentType) {
|
|
1605
|
+
return options.forceContentType;
|
|
1606
|
+
}
|
|
1607
|
+
let contentType = headers.get('content-type');
|
|
1608
|
+
if (!contentType || contentType.includes('application/octet-stream')) {
|
|
1609
|
+
let guess = this.guessContentType(options.resource.value);
|
|
1610
|
+
if (guess) {
|
|
1611
|
+
return guess;
|
|
2107
1612
|
}
|
|
2108
|
-
|
|
2109
|
-
return uri;
|
|
2110
1613
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
*/
|
|
2115
|
-
|
|
2116
|
-
}, {
|
|
2117
|
-
key: "unsupportedProtocol",
|
|
2118
|
-
value: function unsupportedProtocol(uri) {
|
|
2119
|
-
var pcol = Uri.protocol(uri);
|
|
2120
|
-
return pcol === 'tel' || pcol === 'mailto' || pcol === 'urn';
|
|
1614
|
+
let protocol = Uri.protocol(options.resource.value);
|
|
1615
|
+
if (!contentType && ['file', 'chrome'].includes(protocol)) {
|
|
1616
|
+
return 'text/xml';
|
|
2121
1617
|
}
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
* @param options
|
|
2125
|
-
*/
|
|
1618
|
+
return contentType;
|
|
1619
|
+
}
|
|
2126
1620
|
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
1621
|
+
/**
|
|
1622
|
+
* Sends a new request to the specified uri. (Extracted from `onerrorFactory()`)
|
|
1623
|
+
*/
|
|
1624
|
+
redirectToProxy(newURI, options) {
|
|
1625
|
+
this.addStatus(options.req, 'BLOCKED -> Cross-site Proxy to <' + newURI + '>');
|
|
1626
|
+
options.proxyUsed = true;
|
|
1627
|
+
const kb = this.store;
|
|
1628
|
+
const oldReq = options.req; // request metadata blank node
|
|
1629
|
+
|
|
1630
|
+
if (!options.noMeta) {
|
|
1631
|
+
kb.add(oldReq, this.ns.link('redirectedTo'), kb.rdfFactory.namedNode(newURI), oldReq);
|
|
1632
|
+
this.addStatus(oldReq, 'redirected to new request'); // why
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
this.requested[options.resource.value] = 'redirected';
|
|
1636
|
+
this.redirectedTo[options.resource.value] = newURI;
|
|
1637
|
+
let newOptions = Object.assign({}, options);
|
|
1638
|
+
newOptions.baseURI = options.resource.value;
|
|
1639
|
+
return this.fetchUri(newURI, newOptions).then(response => {
|
|
1640
|
+
if (!newOptions.noMeta) {
|
|
1641
|
+
kb.add(oldReq, this.ns.link('redirectedRequest'), newOptions.req, this.appNode);
|
|
1642
|
+
}
|
|
1643
|
+
return response;
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
setRequestTimeout(uri, options) {
|
|
1647
|
+
return new Promise(resolve => {
|
|
1648
|
+
this.timeouts[uri] = (this.timeouts[uri] || []).concat(setTimeout(() => {
|
|
1649
|
+
if (this.isPending(uri) && !options.retriedWithNoCredentials && !options.proxyUsed) {
|
|
1650
|
+
resolve(this.failFetch(options, `Request to ${uri} timed out`, 'timeout'));
|
|
2145
1651
|
}
|
|
1652
|
+
}, this.timeout));
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
addFetchCallback(uri, callback) {
|
|
1656
|
+
if (!this.fetchCallbacks[uri]) {
|
|
1657
|
+
this.fetchCallbacks[uri] = [callback];
|
|
1658
|
+
} else {
|
|
1659
|
+
this.fetchCallbacks[uri].push(callback);
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
acceptString() {
|
|
1663
|
+
let acceptstring = '';
|
|
1664
|
+
for (let mediaType in this.mediatypes) {
|
|
1665
|
+
if (acceptstring !== '') {
|
|
1666
|
+
acceptstring += ', ';
|
|
1667
|
+
}
|
|
1668
|
+
acceptstring += mediaType;
|
|
1669
|
+
for (let property in this.mediatypes[mediaType]) {
|
|
1670
|
+
acceptstring += ';' + property + '=' + this.mediatypes[mediaType][property];
|
|
2146
1671
|
}
|
|
2147
1672
|
}
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
1673
|
+
return acceptstring;
|
|
1674
|
+
}
|
|
1675
|
+
// var updatesVia = new $rdf.UpdatesVia(this) // Subscribe to headers
|
|
1676
|
+
// @@@@@@@@ This is turned off because it causes a websocket to be set up for ANY fetch
|
|
1677
|
+
// whether we want to track it ot not. including ontologies loaed though the XSSproxy
|
|
1678
|
+
}
|
|
2152
1679
|
exports.default = Fetcher;
|
|
2153
1680
|
(0, _defineProperty2.default)(Fetcher, "HANDLERS", void 0);
|
|
2154
1681
|
(0, _defineProperty2.default)(Fetcher, "CONTENT_TYPE_BY_EXT", void 0);
|