nokogiri 1.19.4-java → 1.19.5-java
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.
- checksums.yaml +4 -4
- data/LICENSE-DEPENDENCIES.md +29 -0
- data/ext/java/nokogiri/XmlNode.java +69 -38
- data/ext/java/nokogiri/XmlReader.java +4 -1
- data/ext/java/nokogiri/XmlSchema.java +5 -74
- data/ext/java/nokogiri/XmlXpathContext.java +5 -15
- data/ext/java/nokogiri/internals/NokogiriEntityResolver.java +5 -7
- data/ext/java/nokogiri/internals/NokogiriHelpers.java +68 -0
- data/ext/java/nokogiri/internals/NokogiriXPathContext.java +37 -0
- data/ext/nokogiri/extconf.rb +1 -0
- data/ext/nokogiri/gumbo.c +83 -6
- data/ext/nokogiri/html4_document.c +10 -3
- data/ext/nokogiri/libxml2_polyfill.c +12 -0
- data/ext/nokogiri/nokogiri.c +84 -2
- data/ext/nokogiri/xml_document.c +42 -16
- data/ext/nokogiri/xml_node.c +73 -38
- data/ext/nokogiri/xml_node_set.c +9 -9
- data/ext/nokogiri/xml_reader.c +198 -107
- data/ext/nokogiri/xml_sax_parser.c +3 -3
- data/ext/nokogiri/xml_sax_parser_context.c +38 -7
- data/ext/nokogiri/xml_sax_push_parser.c +12 -0
- data/ext/nokogiri/xml_xpath_context.c +124 -26
- data/ext/nokogiri/xslt_stylesheet.c +123 -27
- data/lib/nokogiri/css/parser.rb +35 -18
- data/lib/nokogiri/css/parser.y +35 -17
- data/lib/nokogiri/css/xpath_visitor.rb +71 -28
- data/lib/nokogiri/html5/document.rb +9 -0
- data/lib/nokogiri/html5/document_fragment.rb +16 -1
- data/lib/nokogiri/html5/node.rb +1 -1
- data/lib/nokogiri/html5.rb +16 -0
- data/lib/nokogiri/nokogiri.jar +0 -0
- data/lib/nokogiri/version/constant.rb +1 -1
- data/lib/nokogiri/xml/attr.rb +2 -0
- data/lib/nokogiri/xml/attribute_decl.rb +2 -1
- data/lib/nokogiri/xml/builder.rb +24 -32
- data/lib/nokogiri/xml/document.rb +1 -0
- data/lib/nokogiri/xml/dtd.rb +2 -1
- data/lib/nokogiri/xml/element_decl.rb +2 -1
- data/lib/nokogiri/xml/entity_decl.rb +2 -1
- data/lib/nokogiri/xml/node.rb +8 -6
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e6d7d6a8cdaeda70bba537e8bb1776407fae18003ff7d1b7a1bd406c9704902a
|
|
4
|
+
data.tar.gz: 4de017065a52bc5fe46178fc40313b0a469a81d6508826e4b75909b07832383d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8203156eb8d63b7e0edb4ea37a1cc3820b349101931e20d83a08bd2f4734004403f63b1ed6b09366dc70907f11cf5404194e8bb901433dd090321e1db2cf57c4
|
|
7
|
+
data.tar.gz: 2709de3b7f5b823e8b051ee81b2c84e46b4b6465d7801d63797004bbca078e39ba7723b2a2471d32c457a465cdb216b063f4854c00b1ca74ef9f19170040b05c
|
data/LICENSE-DEPENDENCIES.md
CHANGED
|
@@ -15,6 +15,7 @@ Note that this document is broken into multiple sections, each of which describe
|
|
|
15
15
|
* [Native WindowsⓇ platform releases ("x64-mingw-ucrt")](#native-windows%E2%93%A1-platform-releases-x64-mingw-ucrt)
|
|
16
16
|
* [JavaⓇ (JRuby) platform release ("java")](#java%E2%93%A1-jruby-platform-release-java)
|
|
17
17
|
- [Appendix: Dependencies' License Texts](#appendix-dependencies-license-texts)
|
|
18
|
+
* [hashmap.c](#hashmapc)
|
|
18
19
|
* [libgumbo](#libgumbo)
|
|
19
20
|
* [libxml2](#libxml2)
|
|
20
21
|
* [libxslt](#libxslt)
|
|
@@ -114,6 +115,34 @@ This section contains a subsection for each potentially-distributed dependency,
|
|
|
114
115
|
Please see previous sections to understand which of these potential dependencies is actually distributed in the gem file you're downloading and using.
|
|
115
116
|
|
|
116
117
|
|
|
118
|
+
### hashmap.c
|
|
119
|
+
|
|
120
|
+
MIT
|
|
121
|
+
|
|
122
|
+
https://github.com/tidwall/hashmap.c/blob/master/LICENSE
|
|
123
|
+
|
|
124
|
+
The MIT License (MIT)
|
|
125
|
+
|
|
126
|
+
Copyright (c) 2020 Joshua J Baker
|
|
127
|
+
|
|
128
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
129
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
130
|
+
the Software without restriction, including without limitation the rights to
|
|
131
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
132
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
133
|
+
subject to the following conditions:
|
|
134
|
+
|
|
135
|
+
The above copyright notice and this permission notice shall be included in all
|
|
136
|
+
copies or substantial portions of the Software.
|
|
137
|
+
|
|
138
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
139
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
140
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
141
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
142
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
143
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
144
|
+
|
|
145
|
+
|
|
117
146
|
### libgumbo
|
|
118
147
|
|
|
119
148
|
Apache 2.0
|
|
@@ -323,7 +323,7 @@ public class XmlNode extends RubyObject
|
|
|
323
323
|
String node_name = rubyStringToString(name);
|
|
324
324
|
String prefix = NokogiriHelpers.getPrefix(node_name);
|
|
325
325
|
String namespace_uri = null;
|
|
326
|
-
if (document.getDocumentElement() != null) {
|
|
326
|
+
if (prefix != null && document.getDocumentElement() != null) {
|
|
327
327
|
namespace_uri = document.getDocumentElement().lookupNamespaceURI(prefix);
|
|
328
328
|
}
|
|
329
329
|
element = document.createElementNS(namespace_uri, node_name);
|
|
@@ -438,25 +438,24 @@ public class XmlNode extends RubyObject
|
|
|
438
438
|
if (ns_inherit.isTrue()) {
|
|
439
439
|
set_namespace(context, ((XmlNode)parent(context)).namespace(context));
|
|
440
440
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
e.setAttribute("xmlns:" + prefix, nsURI);
|
|
441
|
+
} else {
|
|
442
|
+
String currentPrefix = e.getParentNode().lookupPrefix(nsURI);
|
|
443
|
+
String currentURI = e.getParentNode().lookupNamespaceURI(prefix);
|
|
444
|
+
boolean isDefault = e.getParentNode().isDefaultNamespace(nsURI);
|
|
445
|
+
|
|
446
|
+
// add xmlns attribute if this is a new root node or if the node's
|
|
447
|
+
// namespace isn't a default namespace in the new document
|
|
448
|
+
if (e.getParentNode().getNodeType() == Node.DOCUMENT_NODE) {
|
|
449
|
+
// this is the root node, so we must set the namespaces attributes anyway
|
|
450
|
+
e.setAttribute(prefix == null ? "xmlns" : "xmlns:" + prefix, nsURI);
|
|
451
|
+
} else if (prefix == null) {
|
|
452
|
+
// this is a default namespace but isn't the default where this node is being added
|
|
453
|
+
if (!isDefault) { e.setAttribute("xmlns", nsURI); }
|
|
454
|
+
} else if (!prefix.equals(currentPrefix) || !nsURI.equals(currentURI)) {
|
|
455
|
+
// this is a prefixed namespace
|
|
456
|
+
// but doesn't have the same prefix or the prefix is set to a different URI
|
|
457
|
+
e.setAttribute("xmlns:" + prefix, nsURI);
|
|
458
|
+
}
|
|
460
459
|
}
|
|
461
460
|
|
|
462
461
|
if (e.hasAttributes()) {
|
|
@@ -491,6 +490,32 @@ public class XmlNode extends RubyObject
|
|
|
491
490
|
}
|
|
492
491
|
}
|
|
493
492
|
|
|
493
|
+
// if this namespace is a duplicate of what's already in the document, remove it.
|
|
494
|
+
// a "duplicate" here is if the prefix and the URI both match what resolves in the parent.
|
|
495
|
+
if (e.getParentNode().getNodeType() == Node.ELEMENT_NODE) {
|
|
496
|
+
RubyArray<?> nsdefs = this.namespace_definitions(context);
|
|
497
|
+
for (int j = 0 ; j < nsdefs.getLength() ; j++) {
|
|
498
|
+
XmlNamespace ns = (XmlNamespace)nsdefs.get(j);
|
|
499
|
+
|
|
500
|
+
String selfPrefix = ns.getPrefix();
|
|
501
|
+
String selfURI = ns.getHref();
|
|
502
|
+
String parentPrefix = e.getParentNode().lookupPrefix(selfURI);
|
|
503
|
+
String parentURI = e.getParentNode().lookupNamespaceURI(selfPrefix);
|
|
504
|
+
|
|
505
|
+
boolean prefixMatch = ((selfPrefix == null && parentPrefix == null) ||
|
|
506
|
+
(selfPrefix != null && selfPrefix.equals(parentPrefix)));
|
|
507
|
+
boolean uriMatch = ((selfURI == null && parentURI == null) ||
|
|
508
|
+
(selfURI != null && selfURI.equals(parentURI)));
|
|
509
|
+
|
|
510
|
+
if (prefixMatch && uriMatch) {
|
|
511
|
+
String attrName = "xmlns";
|
|
512
|
+
if (selfPrefix != null && !selfPrefix.isEmpty()) { attrName = attrName + ':' + selfPrefix; }
|
|
513
|
+
|
|
514
|
+
e.removeAttribute(attrName);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
494
519
|
if (this.node.hasChildNodes()) {
|
|
495
520
|
relink_namespace(context, getChildren());
|
|
496
521
|
}
|
|
@@ -1175,28 +1200,21 @@ public class XmlNode extends RubyObject
|
|
|
1175
1200
|
public RubyArray<?>
|
|
1176
1201
|
namespace_definitions(ThreadContext context)
|
|
1177
1202
|
{
|
|
1178
|
-
// don't use namespace_definitions cache anymore since
|
|
1179
|
-
//
|
|
1180
|
-
// namespace removals is complicated, so the cache might not be
|
|
1181
|
-
// updated.
|
|
1203
|
+
// don't use namespace_definitions cache anymore since namespaces might be deleted. Reflecting
|
|
1204
|
+
// the result of namespace removals is complicated, so the cache might not be updated.
|
|
1182
1205
|
final XmlDocument doc = document(context.runtime);
|
|
1183
1206
|
if (doc == null) { return context.runtime.newEmptyArray(); }
|
|
1184
1207
|
if (doc instanceof Html4Document) { return context.runtime.newEmptyArray(); }
|
|
1185
1208
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
// if ("http://www.w3.org/2000/xmlns/" == attr.getNamespaceURI()) {
|
|
1196
|
-
// nsdefs.append(XmlNamespace.createFromAttr(context.getRuntime(), attr));
|
|
1197
|
-
// }
|
|
1198
|
-
// }
|
|
1199
|
-
// return nsdefs;
|
|
1209
|
+
RubyArray<?> nsdefs = RubyArray.newArray(context.getRuntime());
|
|
1210
|
+
NamedNodeMap attrs = node.getAttributes();
|
|
1211
|
+
for (int j = 0 ; j < attrs.getLength() ; j++) {
|
|
1212
|
+
Attr attr = (Attr)attrs.item(j);
|
|
1213
|
+
if ("http://www.w3.org/2000/xmlns/" == attr.getNamespaceURI()) {
|
|
1214
|
+
nsdefs.append(XmlNamespace.createFromAttr(context.getRuntime(), attr));
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return nsdefs;
|
|
1200
1218
|
}
|
|
1201
1219
|
|
|
1202
1220
|
/**
|
|
@@ -1506,6 +1524,19 @@ public class XmlNode extends RubyObject
|
|
|
1506
1524
|
// and keep the return value. -mbklein
|
|
1507
1525
|
String new_name = NokogiriHelpers.newQName(ns.getPrefix(), node);
|
|
1508
1526
|
this.node = NokogiriHelpers.renameNode(node, ns.getHref(), new_name);
|
|
1527
|
+
|
|
1528
|
+
if (node instanceof Element) {
|
|
1529
|
+
Element e = (Element) node;
|
|
1530
|
+
String prefix = ns.getPrefix();
|
|
1531
|
+
String attrName = prefix == null ? "xmlns" : "xmlns:" + prefix;
|
|
1532
|
+
Node parent = e.getParentNode();
|
|
1533
|
+
boolean inScope = "xml".equals(prefix) ||
|
|
1534
|
+
e.hasAttribute(attrName) ||
|
|
1535
|
+
(parent != null && parent.lookupNamespaceURI(prefix) != null);
|
|
1536
|
+
if (!inScope) {
|
|
1537
|
+
e.setAttributeNS("http://www.w3.org/2000/xmlns/", attrName, ns.getHref());
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1509
1540
|
}
|
|
1510
1541
|
|
|
1511
1542
|
clearXpathContext(getNode());
|
|
@@ -31,6 +31,7 @@ import org.jruby.RubyBoolean;
|
|
|
31
31
|
import org.jruby.RubyClass;
|
|
32
32
|
import org.jruby.RubyFixnum;
|
|
33
33
|
import org.jruby.RubyObject;
|
|
34
|
+
import org.jruby.RubyString;
|
|
34
35
|
import org.jruby.anno.JRubyClass;
|
|
35
36
|
import org.jruby.anno.JRubyMethod;
|
|
36
37
|
import org.jruby.exceptions.RaiseException;
|
|
@@ -253,7 +254,9 @@ public class XmlReader extends RubyObject
|
|
|
253
254
|
// use the default options RECOVER | NONET
|
|
254
255
|
options = new ParserContext.Options(2048 | 1);
|
|
255
256
|
}
|
|
256
|
-
|
|
257
|
+
// The parser reads lazily, so hand it a copy the caller cannot change.
|
|
258
|
+
RubyString frozenSource = args[0].convertToString().newFrozen();
|
|
259
|
+
IRubyObject stringIO = runtime.getClass("StringIO").newInstance(context, frozenSource, Block.NULL_BLOCK);
|
|
257
260
|
InputStream in = new IOInputStream(stringIO);
|
|
258
261
|
reader.setInput(context, in, url, options);
|
|
259
262
|
return reader;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
package nokogiri;
|
|
2
2
|
|
|
3
3
|
import static nokogiri.internals.NokogiriHelpers.adjustSystemIdIfNecessary;
|
|
4
|
+
import static nokogiri.internals.NokogiriHelpers.effectiveResourceIsLocal;
|
|
4
5
|
import static nokogiri.internals.NokogiriHelpers.getNokogiriClass;
|
|
5
6
|
|
|
6
7
|
import java.io.IOException;
|
|
@@ -8,9 +9,6 @@ import java.io.InputStream;
|
|
|
8
9
|
import java.io.Reader;
|
|
9
10
|
import java.io.StringReader;
|
|
10
11
|
|
|
11
|
-
import java.net.URI;
|
|
12
|
-
import java.net.URISyntaxException;
|
|
13
|
-
|
|
14
12
|
import javax.xml.XMLConstants;
|
|
15
13
|
import javax.xml.transform.Source;
|
|
16
14
|
import javax.xml.transform.dom.DOMSource;
|
|
@@ -288,6 +286,10 @@ public class XmlSchema extends RubyObject
|
|
|
288
286
|
String systemId,
|
|
289
287
|
String baseURI)
|
|
290
288
|
{
|
|
289
|
+
// We enforce NONET for schema resolution by hand because Xerces-J (the JAXP implementation
|
|
290
|
+
// backing XML::Schema on JRuby) does not implement the standard JAXP property
|
|
291
|
+
// XMLConstants.ACCESS_EXTERNAL_SCHEMA — so we cannot simply restrict external access on the
|
|
292
|
+
// SchemaFactory and must classify each resolved resource in the LSResourceResolver instead.
|
|
291
293
|
if (noNet && !effectiveResourceIsLocal(systemId, baseURI)) {
|
|
292
294
|
try {
|
|
293
295
|
this.errorHandler.warning(new SAXParseException(String.format("Attempt to load network entity '%s'", systemId), null));
|
|
@@ -304,35 +306,6 @@ public class XmlSchema extends RubyObject
|
|
|
304
306
|
}
|
|
305
307
|
}
|
|
306
308
|
|
|
307
|
-
// We enforce NONET for schema resolution by hand because Xerces-J (the JAXP implementation
|
|
308
|
-
// backing XML::Schema on JRuby) does not implement the standard JAXP property
|
|
309
|
-
// XMLConstants.ACCESS_EXTERNAL_SCHEMA — so we cannot simply restrict external access on the
|
|
310
|
-
// SchemaFactory and must classify each resolved resource in the LSResourceResolver instead.
|
|
311
|
-
//
|
|
312
|
-
// Decides whether a schema-import resource may be resolved while NONET is on: true means
|
|
313
|
-
// local (allowed), false means a network resource (blocked). A relative systemId inherits
|
|
314
|
-
// its document's base, so it is resolved against baseURI before classification — a relative
|
|
315
|
-
// import under a remote base is a network fetch even though the systemId alone looks local.
|
|
316
|
-
private static boolean
|
|
317
|
-
effectiveResourceIsLocal(String systemId, String baseURI)
|
|
318
|
-
{
|
|
319
|
-
// a null systemId means there is nothing external to resolve
|
|
320
|
-
if (systemId == null) {
|
|
321
|
-
return true;
|
|
322
|
-
}
|
|
323
|
-
try {
|
|
324
|
-
URI uri = new URI(systemId);
|
|
325
|
-
if (baseURI != null && !baseURI.isEmpty()) {
|
|
326
|
-
uri = new URI(baseURI).resolve(uri);
|
|
327
|
-
}
|
|
328
|
-
return isLocalResource(uri);
|
|
329
|
-
} catch (URISyntaxException | IllegalArgumentException e) {
|
|
330
|
-
// fail closed: an unparseable base or systemId (e.g. a raw UNC path "\\host\share") is
|
|
331
|
-
// not provably local, and the JVM's file/URL handling may still reach the network
|
|
332
|
-
return false;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
309
|
// Test seam for the Ruby suite: local_resource?(systemId, baseURI = nil).
|
|
337
310
|
@JRubyMethod(meta = true, name = "local_resource?", required = 1, optional = 1, visibility = Visibility.PRIVATE)
|
|
338
311
|
public static IRubyObject
|
|
@@ -343,48 +316,6 @@ public class XmlSchema extends RubyObject
|
|
|
343
316
|
return context.runtime.newBoolean(effectiveResourceIsLocal(systemId, baseURI));
|
|
344
317
|
}
|
|
345
318
|
|
|
346
|
-
// Classifies an already-parsed URI. Local is a missing scheme, or the "file" scheme, with
|
|
347
|
-
// no remote authority and no UNC-shaped path. This is intentionally stricter than libxml2's
|
|
348
|
-
// xmlNoNetExternalEntityLoader, which folds a remote host (file://host/...) into a local
|
|
349
|
-
// path rather than rejecting it.
|
|
350
|
-
//
|
|
351
|
-
// TODO: a Windows drive-letter path like "C:\path" parses as scheme "c" and would be
|
|
352
|
-
// blocked; support those if we need it later.
|
|
353
|
-
private static boolean
|
|
354
|
-
isLocalResource(URI uri)
|
|
355
|
-
{
|
|
356
|
-
// only a missing scheme (a relative or absolute path) or file: can be local; any
|
|
357
|
-
// other scheme is a network resource
|
|
358
|
-
String scheme = uri.getScheme();
|
|
359
|
-
if (scheme != null && !scheme.equalsIgnoreCase("file")) {
|
|
360
|
-
return false;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// an opaque "file:" URI (e.g. file:foo, with no "//") is not a usable local path; reject
|
|
364
|
-
// it, matching libxml2, which does not resolve that form as a local file either
|
|
365
|
-
if (uri.isOpaque()) {
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// a non-empty, non-localhost authority is a remote host — file://host/path, or the
|
|
370
|
-
// schemeless network-path form //host/path. Stricter than libxml2, which folds such a
|
|
371
|
-
// host into a (failing) local path.
|
|
372
|
-
String authority = uri.getRawAuthority();
|
|
373
|
-
if (authority != null && !authority.isEmpty() && !authority.equalsIgnoreCase("localhost")) {
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// reject UNC-shaped paths even under an allowed authority: file:////host/share,
|
|
378
|
-
// file://localhost//host/share, and %2f/%5c-encoded variants. getPath() is decoded, so
|
|
379
|
-
// the encoded forms are normalized before this check.
|
|
380
|
-
String path = uri.getPath();
|
|
381
|
-
if (path != null && (path.startsWith("//") || path.indexOf('\\') >= 0)) {
|
|
382
|
-
return false;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return true;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
319
|
private class SchemaLSInput implements LSInput
|
|
389
320
|
{
|
|
390
321
|
protected String fPublicId;
|
|
@@ -20,10 +20,10 @@ import org.jruby.anno.JRubyMethod;
|
|
|
20
20
|
import org.jruby.exceptions.RaiseException;
|
|
21
21
|
import org.jruby.runtime.ThreadContext;
|
|
22
22
|
import org.jruby.runtime.builtin.IRubyObject;
|
|
23
|
-
import org.jruby.util.SafePropertyAccessor;
|
|
24
23
|
import org.w3c.dom.Node;
|
|
25
24
|
|
|
26
25
|
import nokogiri.internals.NokogiriNamespaceContext;
|
|
26
|
+
import nokogiri.internals.NokogiriXPathContext;
|
|
27
27
|
import nokogiri.internals.NokogiriXPathFunctionResolver;
|
|
28
28
|
import nokogiri.internals.NokogiriXPathVariableResolver;
|
|
29
29
|
|
|
@@ -41,16 +41,6 @@ public class XmlXpathContext extends RubyObject
|
|
|
41
41
|
{
|
|
42
42
|
private static final long serialVersionUID = 1L;
|
|
43
43
|
|
|
44
|
-
static
|
|
45
|
-
{
|
|
46
|
-
final String DTMManager = "org.apache.xml.dtm.DTMManager";
|
|
47
|
-
if (SafePropertyAccessor.getProperty(DTMManager) == null) {
|
|
48
|
-
try { // use patched "org.apache.xml.dtm.ref.DTMManagerDefault"
|
|
49
|
-
System.setProperty(DTMManager, nokogiri.internals.XalanDTMManagerPatch.class.getName());
|
|
50
|
-
} catch (SecurityException ex) { /* no-op - will work although might be slower */ }
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
44
|
/**
|
|
55
45
|
* user-data key for (cached) {@link XPathContext}
|
|
56
46
|
*/
|
|
@@ -82,7 +72,7 @@ public class XmlXpathContext extends RubyObject
|
|
|
82
72
|
rbNew(ThreadContext context, IRubyObject klazz, IRubyObject node)
|
|
83
73
|
{
|
|
84
74
|
try {
|
|
85
|
-
return new XmlXpathContext(context.runtime, (RubyClass) klazz, (
|
|
75
|
+
return new XmlXpathContext(context.runtime, (RubyClass) klazz, XmlNode.asXmlNode(context, node));
|
|
86
76
|
} catch (IllegalArgumentException e) {
|
|
87
77
|
throw context.getRuntime().newRuntimeError(e.getMessage());
|
|
88
78
|
}
|
|
@@ -185,7 +175,7 @@ public class XmlXpathContext extends RubyObject
|
|
|
185
175
|
public IRubyObject
|
|
186
176
|
set_node(ThreadContext context, IRubyObject rb_node)
|
|
187
177
|
{
|
|
188
|
-
this.context = (
|
|
178
|
+
this.context = XmlNode.asXmlNode(context, rb_node);
|
|
189
179
|
return rb_node;
|
|
190
180
|
}
|
|
191
181
|
|
|
@@ -268,8 +258,8 @@ public class XmlXpathContext extends RubyObject
|
|
|
268
258
|
private static XPathContext
|
|
269
259
|
newXPathContext(final NokogiriXPathFunctionResolver functionResolver)
|
|
270
260
|
{
|
|
271
|
-
if (functionResolver == null) { return new
|
|
272
|
-
return new
|
|
261
|
+
if (functionResolver == null) { return new NokogiriXPathContext(); }
|
|
262
|
+
return new NokogiriXPathContext(new JAXPExtensionsProvider(functionResolver));
|
|
273
263
|
}
|
|
274
264
|
|
|
275
265
|
private boolean
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package nokogiri.internals;
|
|
2
2
|
|
|
3
|
+
import static nokogiri.internals.NokogiriHelpers.effectiveResourceIsLocal;
|
|
4
|
+
|
|
3
5
|
import java.io.ByteArrayInputStream;
|
|
4
6
|
import java.io.File;
|
|
5
7
|
import java.io.IOException;
|
|
@@ -103,12 +105,12 @@ public class NokogiriEntityResolver implements EntityResolver2
|
|
|
103
105
|
} else if (!name.equals("[dtd]") && !options.noEnt) {
|
|
104
106
|
return emptyInputSource(s);
|
|
105
107
|
}
|
|
106
|
-
|
|
107
|
-
URI uri = URI.create(systemId);
|
|
108
|
-
if (options.noNet && uri.getHost() != null) {
|
|
108
|
+
if (options.noNet && !effectiveResourceIsLocal(systemId, baseURI)) {
|
|
109
109
|
addError("Attempt to load network entity " + systemId);
|
|
110
110
|
return emptyInputSource(s);
|
|
111
111
|
}
|
|
112
|
+
String adjustedSystemId;
|
|
113
|
+
URI uri = URI.create(systemId);
|
|
112
114
|
// if this is a url or absolute file name then use it
|
|
113
115
|
if (uri.isAbsolute() && !uri.isOpaque()) {
|
|
114
116
|
adjustedSystemId = uri.toURL().toString();
|
|
@@ -116,10 +118,6 @@ public class NokogiriEntityResolver implements EntityResolver2
|
|
|
116
118
|
adjustedSystemId = uri.getPath();
|
|
117
119
|
} else if (baseURI != null) {
|
|
118
120
|
URI baseuri = URI.create(baseURI);
|
|
119
|
-
if (options.noNet && baseuri.getHost() != null) {
|
|
120
|
-
addError("Attempt to load network entity " + systemId);
|
|
121
|
-
return emptyInputSource(s);
|
|
122
|
-
}
|
|
123
121
|
if (baseuri.getHost() == null) {
|
|
124
122
|
// this is a local file
|
|
125
123
|
adjustedSystemId = join(baseuri.getPath(), uri.getPath()).getCanonicalPath();
|
|
@@ -4,6 +4,8 @@ import java.io.ByteArrayInputStream;
|
|
|
4
4
|
import java.io.File;
|
|
5
5
|
import java.lang.reflect.InvocationTargetException;
|
|
6
6
|
import java.lang.reflect.Method;
|
|
7
|
+
import java.net.URI;
|
|
8
|
+
import java.net.URISyntaxException;
|
|
7
9
|
import java.nio.ByteBuffer;
|
|
8
10
|
import java.nio.CharBuffer;
|
|
9
11
|
import java.nio.charset.Charset;
|
|
@@ -674,6 +676,72 @@ public class NokogiriHelpers
|
|
|
674
676
|
|
|
675
677
|
private static final Set<String> CharsetNames = Charset.availableCharsets().keySet();
|
|
676
678
|
|
|
679
|
+
// Decides whether an external resource may be resolved while NONET is on: true means
|
|
680
|
+
// local (allowed), false means a network resource (blocked). A relative systemId inherits
|
|
681
|
+
// its document's base, so it is resolved against baseURI before classification — a relative
|
|
682
|
+
// reference under a remote base is a network fetch even though the systemId alone looks local.
|
|
683
|
+
public static boolean
|
|
684
|
+
effectiveResourceIsLocal(String systemId, String baseURI)
|
|
685
|
+
{
|
|
686
|
+
// a null systemId means there is nothing external to resolve
|
|
687
|
+
if (systemId == null) {
|
|
688
|
+
return true;
|
|
689
|
+
}
|
|
690
|
+
try {
|
|
691
|
+
URI uri = new URI(systemId);
|
|
692
|
+
if (baseURI != null && !baseURI.isEmpty()) {
|
|
693
|
+
uri = new URI(baseURI).resolve(uri);
|
|
694
|
+
}
|
|
695
|
+
return isLocalResource(uri);
|
|
696
|
+
} catch (URISyntaxException | IllegalArgumentException e) {
|
|
697
|
+
// fail closed: an unparseable base or systemId (e.g. a raw UNC path "\\host\share") is
|
|
698
|
+
// not provably local, and the JVM's file/URL handling may still reach the network
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// Classifies an already-parsed URI. Local is a missing scheme, or the "file" scheme, with
|
|
704
|
+
// no remote authority and no UNC-shaped path. This is intentionally stricter than libxml2's
|
|
705
|
+
// xmlNoNetExternalEntityLoader, which folds a remote host (file://host/...) into a local
|
|
706
|
+
// path rather than rejecting it.
|
|
707
|
+
//
|
|
708
|
+
// TODO: a Windows drive-letter path like "C:\path" parses as scheme "c" and would be
|
|
709
|
+
// blocked; support those if we need it later.
|
|
710
|
+
private static boolean
|
|
711
|
+
isLocalResource(URI uri)
|
|
712
|
+
{
|
|
713
|
+
// only a missing scheme (a relative or absolute path) or file: can be local; any
|
|
714
|
+
// other scheme is a network resource
|
|
715
|
+
String scheme = uri.getScheme();
|
|
716
|
+
if (scheme != null && !scheme.equalsIgnoreCase("file")) {
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// an opaque "file:" URI (e.g. file:foo, with no "//") is not a usable local path; reject
|
|
721
|
+
// it, matching libxml2, which does not resolve that form as a local file either
|
|
722
|
+
if (uri.isOpaque()) {
|
|
723
|
+
return false;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// a non-empty, non-localhost authority is a remote host — file://host/path, or the
|
|
727
|
+
// schemeless network-path form //host/path. Stricter than libxml2, which folds such a
|
|
728
|
+
// host into a (failing) local path.
|
|
729
|
+
String authority = uri.getRawAuthority();
|
|
730
|
+
if (authority != null && !authority.isEmpty() && !authority.equalsIgnoreCase("localhost")) {
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// reject UNC-shaped paths even under an allowed authority: file:////host/share,
|
|
735
|
+
// file://localhost//host/share, and %2f/%5c-encoded variants. getPath() is decoded, so
|
|
736
|
+
// the encoded forms are normalized before this check.
|
|
737
|
+
String path = uri.getPath();
|
|
738
|
+
if (path != null && (path.startsWith("//") || path.indexOf('\\') >= 0)) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return true;
|
|
743
|
+
}
|
|
744
|
+
|
|
677
745
|
public static String
|
|
678
746
|
adjustSystemIdIfNecessary(String currentDir, String scriptFileName, String baseURI, String systemId)
|
|
679
747
|
{
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package nokogiri.internals;
|
|
2
|
+
|
|
3
|
+
import org.apache.xml.dtm.DTMManager;
|
|
4
|
+
import org.apache.xpath.XPathContext;
|
|
5
|
+
import org.apache.xpath.objects.XMLStringFactoryImpl;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* An XPathContext that uses XalanDTMManagerPatch without looking it up by class name.
|
|
9
|
+
*
|
|
10
|
+
* Xalan's DTMManager.newInstance() looks up the manager class in the thread's context class loader
|
|
11
|
+
* and in the class loader that loaded Xalan. In a servlet container with Xalan in WEB-INF/lib,
|
|
12
|
+
* both are the webapp class loader, which cannot see nokogiri's classes.
|
|
13
|
+
*/
|
|
14
|
+
public final class NokogiriXPathContext extends XPathContext
|
|
15
|
+
{
|
|
16
|
+
public
|
|
17
|
+
NokogiriXPathContext()
|
|
18
|
+
{
|
|
19
|
+
super(false);
|
|
20
|
+
m_dtmManager = newDTMManager();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public
|
|
24
|
+
NokogiriXPathContext(Object owner)
|
|
25
|
+
{
|
|
26
|
+
super(owner, false);
|
|
27
|
+
m_dtmManager = newDTMManager();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private static DTMManager
|
|
31
|
+
newDTMManager()
|
|
32
|
+
{
|
|
33
|
+
DTMManager manager = new XalanDTMManagerPatch();
|
|
34
|
+
manager.setXMLStringFactory(XMLStringFactoryImpl.getFactory());
|
|
35
|
+
return manager;
|
|
36
|
+
}
|
|
37
|
+
}
|
data/ext/nokogiri/extconf.rb
CHANGED
|
@@ -1125,6 +1125,7 @@ end
|
|
|
1125
1125
|
have_func("xmlCtxtSetOptions") # introduced in libxml2 2.13.0
|
|
1126
1126
|
have_func("xmlCtxtGetOptions") # introduced in libxml2 2.14.0
|
|
1127
1127
|
have_func("xmlSwitchEncodingName") # introduced in libxml2 2.13.0
|
|
1128
|
+
have_func("xmlAddIDSafe") # introduced in libxml2 2.13.0
|
|
1128
1129
|
have_func("rb_category_warning") # introduced in Ruby 3.0 but had trouble resolving this symbol in truffleruby
|
|
1129
1130
|
|
|
1130
1131
|
other_library_versions_string = OTHER_LIBRARY_VERSIONS.map { |k, v| [k, v].join(":") }.join(",")
|