canon 0.3.46 → 0.3.48

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dc57b150c1a0a2b9179f4b88a78c22aeb1529aa74d30857d8ca71a6159d6639
4
- data.tar.gz: 65db8a7cadb8718b11a475858d3bfd5d4adcf0a4c738a7c940a6dfa60a6bfd3e
3
+ metadata.gz: fcfa53c5436e38941e6c789536bf9c268fb5b587930aeaca6020c22993def0a2
4
+ data.tar.gz: a814221d4dd934e35f8f6eb1169f8694fadf2e2fd60e49a9f8f61e6355ff9853
5
5
  SHA512:
6
- metadata.gz: d411dc92e7978a904f303a95397f301286e9a12a3fc3732bb91919c2564375221b12cb13db64198f41942edeb5bbe2dfc8512b173cbfbdab44d27409d5a009a9
7
- data.tar.gz: eaa339eae29ca147aa6ee9a5cecf9a328e69fc9b1f64b3acb742d11f4d451bef89efc11cde012e06e15f21b10ec09f95fbf36e0456c718ba925c015e47dba0ce
6
+ metadata.gz: 1ac2772108ab1d9cae92a479a98c94cbc02bff2a431a64e3dc9052ff4df5ec595a38c81849c3d9ddc1c1329b6a86bdfbb7d3aeae6b5bbacfa2d6d8d283acc0a6
7
+ data.tar.gz: 7794b9a9392eaa18bb43b85ec7a2e830d3c0f172bfd827e13b7e3f6290c82cb6b3491312090f8230671c1a7442e722a7c1b3d66a44398965b89ab4664ec11a4d
data/CLAUDE.md CHANGED
@@ -145,7 +145,7 @@ Engine A/B testing: `CANON_XML_BACKEND=nokogiri bundle exec rspec` (or `=moxml`
145
145
 
146
146
  ### C14N Engines
147
147
 
148
- `Canon::Xml::C14n.canonicalize` stays on canon's Ruby C14N 1.1 processor by default. leptris' native C-side C14N 1.1 is ~50x faster on large documents and byte-identical on the main corpus, but diverges from the spec on edge cases (attribute ordering, prefix preservation, `>`/tab escaping, document-level PIs leptris#1015, all pinned in `spec/canon/xml/c14n_engine_parity_spec.rb`). `CANON_C14N_BACKEND=leptris` opts in; when the parity gate runs clean the default flips. `canonicalize_subset` and `with_comments: true` always use the Ruby processor.
148
+ `Canon::Xml::C14n.canonicalize` uses leptris' native C-side C14N 1.1 by DEFAULT (since libleptris 1.9.178 / gem 1.9.178.0) 23x faster than the Ruby processor through canon's API (1MB document). The native parse runs `noblanks: true` (compact bytes, matching the Ruby lane's product), relative namespace URIs raise identically, and document-level PIs serialize in spec-correct document order (the Ruby processor's root-first order was non-conformant for prolog PIs). `CANON_C14N_BACKEND=ruby` forces the Ruby processor. `canonicalize_subset` and `with_comments: true` always use the Ruby processor. The parity spec (`spec/canon/xml/c14n_engine_parity_spec.rb`) pins byte-identity; its pending cases track intentional divergences (document-order PIs) and the canon-side CR-reference finding.
149
149
 
150
150
  ### YAML Engines
151
151
 
data/lib/canon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canon
4
- VERSION = "0.3.46"
4
+ VERSION = "0.3.48"
5
5
  end
@@ -23,32 +23,37 @@ module Canon
23
23
  end
24
24
 
25
25
  # leptris' C-side C14N 1.1 — 23x faster than the Ruby processor
26
- # through canon's own API (1MB document). libleptris 1.9.164
27
- # closed four of the five leptris#1015 families (attribute
28
- # ordering, prefix loss and rebinding, `>` and TAB escaping —
29
- # unpinned in the parity spec since gem 1.9.174.0). A local
30
- # default-flip attempt surfaced three MORE divergences the
31
- # edge corpus did not cover, so the lane stays opt-in
32
- # (CANON_C14N_BACKEND=leptris) until they close (leptris#1096):
33
- # redundant namespace redeclarations are kept (Ruby removes
34
- # them), xmlns:xml with the standard URI is kept (Ruby omits
35
- # it), and document-level processing instructions are dropped.
36
- # The Ruby lane additionally validates relative namespace URIs
37
- # at parse time a future flip must carry that check into the
38
- # native wrapper. Comments mode keeps the Ruby path regardless.
26
+ # through canon's own API (1MB document) and the DEFAULT lane
27
+ # since libleptris 1.9.178 (gem 1.9.178.0): the leptris#1117
28
+ # families are closed by the native parse-policy knob
29
+ # (`noblanks: true` same compact bytes as the Ruby lane's
30
+ # parse) and by the canonicalizer itself (whitespace-only PI
31
+ # data dropped, document-level "\n" separators inserted). The
32
+ # one residual byte difference vs the Ruby lane is intentional
33
+ # and a correctness improvement: document-level PIs now
34
+ # serialize in document order (REC-xml-c14n 2.1) instead of
35
+ # the Ruby lane's non-conformant root-first reorder. Relative
36
+ # namespace URIs raise exactly as the Ruby lane does.
37
+ # Comments mode keeps the Ruby path regardless (the native
38
+ # seam exposes no with-comments form). CANON_C14N_BACKEND=ruby
39
+ # forces the stdlib lane.
39
40
  def self.native_canonicalize(xml, with_comments)
40
41
  return nil if with_comments
41
42
  return nil if RUBY_ENGINE == "opal"
42
- return nil unless ENV["CANON_C14N_BACKEND"].to_s.casecmp("leptris").zero?
43
+ return nil if ENV["CANON_C14N_BACKEND"].to_s.casecmp("ruby").zero?
43
44
  return nil unless Canon::XmlBackend.moxml? &&
44
45
  Canon::XmlParsing.moxml_adapter_name == :leptris
45
46
  return nil unless native_c14n_available?
46
47
 
47
- doc = Canon::XmlParsing.moxml_context.parse(xml, readonly: true,
48
- strict: false)
48
+ validate_relative_namespaces!(xml)
49
+
50
+ doc = Canon::XmlParsing.moxml_context.parse(xml,
51
+ readonly: true,
52
+ strict: false,
53
+ noblanks: true)
49
54
  begin
50
- doc.native.canonicalize(::Leptris::XML::FFI::C14N_1_1, nil,
51
- mode: ::Leptris::XML::FFI::C14N_MODE_CANONICAL)
55
+ doc.native.c14n(::Leptris::XML::FFI::C14N_1_1, nil,
56
+ mode: ::Leptris::XML::FFI::C14N_MODE_CANONICAL)
52
57
  ensure
53
58
  doc.free
54
59
  end
@@ -58,6 +63,25 @@ module Canon
58
63
  nil
59
64
  end
60
65
 
66
+ # Canon::Error parity with the Ruby lane, whose parse rejects
67
+ # relative namespace URIs. A declaration-shaped scan; a
68
+ # relative-URI-shaped string inside CDATA is the only false
69
+ # positive this can produce.
70
+ RELATIVE_NS_DECL = /xmlns(?::[\w.-]+)?="([^"]*)"/
71
+ URI_SCHEME = %r{\A[a-zA-Z][a-zA-Z0-9+.-]*:}
72
+
73
+ def self.validate_relative_namespaces!(xml)
74
+ return unless xml.is_a?(String)
75
+
76
+ xml.scan(RELATIVE_NS_DECL) do |(uri)|
77
+ next if uri.nil? || uri.empty?
78
+
79
+ unless uri.match?(URI_SCHEME)
80
+ raise Canon::Error, "Relative namespace URI not allowed: #{uri}"
81
+ end
82
+ end
83
+ end
84
+
61
85
  def self.native_c14n_available?
62
86
  return @native_c14n_available unless @native_c14n_available.nil?
63
87
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.46
4
+ version: 0.3.48
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.