Skip to content

Commit 952ff44

Browse files
committed
fix: ensure serialization still works with pseudo-IO classes
Fixes #2773
1 parent 9e137bb commit 952ff44

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

Diff for: CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ Nokogiri follows [Semantic Versioning](https://semver.org/), please see the [REA
44

55
---
66

7+
## 1.14.1 / unreleased
8+
9+
### Fixed
10+
11+
* Serializing documents now works again with pseudo-IO objects that don't support IO's encoding API (like rubyzip's `Zip::OutputStream`). This was a regression in v1.14.0 due to the fix for [#752](https://github.com/sparklemotion/nokogiri/issues/752) in [#2434](https://github.com/sparklemotion/nokogiri/issues/2434), and was not completely fixed by [#2753](https://github.com/sparklemotion/nokogiri/issues/2753). [[#2773](https://github.com/sparklemotion/nokogiri/issues/2773)]
12+
13+
2e260f53e6b84b8f9c1b115b0ded85eebc8155d7
14+
15+
716
## 1.14.0 / 2023-01-12
817

918
### Notable Changes

Diff for: Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ group :development do
2424
gem "minitest-reporters", "= 1.5.0"
2525
gem "ruby_memcheck", "1.2.0" unless RUBY_PLATFORM == "java"
2626
gem "simplecov", "= 0.21.2"
27+
gem "rubyzip", "~> 2.3.2"
2728

2829
# rubocop
2930
if Gem::Requirement.new("~> 3.0").satisfied_by?(Gem::Version.new(RUBY_VERSION))

Diff for: ext/nokogiri/nokogiri.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,13 @@ noko_io_write(void *io, char *c_buffer, int c_buffer_len)
112112
{
113113
VALUE rb_args[2], rb_n_bytes_written;
114114
VALUE rb_io = (VALUE)io;
115-
VALUE rb_enc = rb_funcall(rb_io, id_external_encoding, 0);
116-
rb_encoding *io_encoding = RB_NIL_P(rb_enc) ? rb_ascii8bit_encoding() : rb_to_encoding(rb_enc);
115+
VALUE rb_enc = Qnil;
116+
rb_encoding *io_encoding;
117+
118+
if (rb_respond_to(rb_io, id_external_encoding)) {
119+
rb_enc = rb_funcall(rb_io, id_external_encoding, 0);
120+
}
121+
io_encoding = RB_NIL_P(rb_enc) ? rb_ascii8bit_encoding() : rb_to_encoding(rb_enc);
117122

118123
rb_args[0] = rb_io;
119124
rb_args[1] = rb_enc_str_new(c_buffer, (long)c_buffer_len, io_encoding);

Diff for: test/xml/test_document_encoding.rb

+35
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,41 @@ class TestDocumentEncoding < Nokogiri::TestCase
8787
assert_equal(Encoding::UTF_16, output.encoding)
8888
assert_equal(utf16_document.bytesize, output.bytesize)
8989
end
90+
91+
describe "pseudo-IO" do
92+
it "serializes correctly with Zip::OutputStream objects" do
93+
# https://github.com/sparklemotion/nokogiri/issues/2773
94+
require "zip"
95+
96+
xml = <<~XML
97+
<?xml version="1.0" encoding="UTF-8"?>
98+
<root>
99+
<bar>A</bar>
100+
</root>
101+
XML
102+
103+
Dir.mktmpdir do |tmpdir|
104+
zipfile_path = File.join(tmpdir, "test.zip")
105+
106+
Zip::OutputStream.open(zipfile_path) do |io|
107+
io.put_next_entry("test-utf8.xml")
108+
Nokogiri::XML(xml).write_to(io, encoding: "UTF-8")
109+
end
110+
111+
Zip::InputStream.open(zipfile_path) do |io|
112+
entry = io.get_next_entry
113+
assert_equal("test-utf8.xml", entry.name)
114+
output = io.read
115+
116+
# no final newline on jruby. descriptive, not prescriptive.
117+
expected_length = Nokogiri.jruby? ? xml.bytesize - 1 : xml.bytesize
118+
119+
assert_equal(Encoding::UTF_8, output.encoding)
120+
assert_equal(expected_length, output.bytesize)
121+
end
122+
end
123+
end
124+
end
90125
end
91126
end
92127
end

0 commit comments

Comments
 (0)