Skip to content

Commit

Permalink
Fix Unicode encoding issues with detailed_message
Browse files Browse the repository at this point in the history
  • Loading branch information
imjoehaines committed Mar 13, 2024
1 parent 13040d4 commit 27beed6
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Changelog
=========

## TBD

* Fix Unicode encoding issues when using `Exception#detailed_message` (Ruby 3.2+)
| [#817](https://github.com/bugsnag/bugsnag-ruby/pull/817)

## v6.26.3 (24 January 2024)

* Handle mailto links in `Cleaner#clean_url`
Expand Down
9 changes: 8 additions & 1 deletion lib/bugsnag/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,15 @@ def error_message(exception, class_name)
exception.detailed_message
end

# the string returned by 'detailed_message' defaults to 'ASCII_8BIT' but
# is actually UTF-8 encoded; we can't convert the encoding normally as its
# internal encoding doesn't match its actual encoding
message.force_encoding(::Encoding::UTF_8) if message.encoding == ::Encoding::ASCII_8BIT

# remove the class name to be consistent with Exception#message
message.sub(" (#{class_name})", '')
message.sub!(" (#{class_name})".encode(message.encoding), "") rescue nil

message
end

def generate_raw_exceptions(exception)
Expand Down
92 changes: 77 additions & 15 deletions spec/report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ def detailed_message
end
end

class ExceptionWithDetailedMessageReturningEncodedString < Exception
def initialize(message, encoding)
super(message)
@encoding = encoding
end

def detailed_message
"abc #{self} xyz".encode(@encoding)
end
end

shared_examples "Report or Event tests" do |class_to_test|
context "metadata" do
include_examples(
Expand Down Expand Up @@ -1465,24 +1476,75 @@ def detailed_message
}
end

it "uses Exception#detailed_message if available" do
Bugsnag.notify(ExceptionWithDetailedMessage.new("some message"))
context "#detailed_message" do
it "uses Exception#detailed_message if available" do
Bugsnag.notify(ExceptionWithDetailedMessage.new("some message"))

expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)
expect(exception["errorClass"]).to eq("ExceptionWithDetailedMessage")
expect(exception["message"]).to eq("some message with some extra detail")
}
end
expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)
expect(exception["errorClass"]).to eq("ExceptionWithDetailedMessage")
expect(exception["message"]).to eq("some message with some extra detail")
}
end

it "handles implementations of Exception#detailed_message with no 'highlight' parameter" do
Bugsnag.notify(ExceptionWithDetailedMessageButNoHighlight.new("some message"))
it "handles implementations of Exception#detailed_message with no 'highlight' parameter" do
Bugsnag.notify(ExceptionWithDetailedMessageButNoHighlight.new("some message"))

expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)
expect(exception["errorClass"]).to eq("ExceptionWithDetailedMessageButNoHighlight")
expect(exception["message"]).to eq("detail about 'some message'")
}
expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)
expect(exception["errorClass"]).to eq("ExceptionWithDetailedMessageButNoHighlight")
expect(exception["message"]).to eq("detail about 'some message'")
}
end

it "converts ASCII_8BIT encoding to UTF-8" do
Bugsnag.notify(Exception.new("大好き\n大好き"))

expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)
expect(exception["message"]).to eq("大好き\n大好き")
}
end

it "leaves UTF-8 strings as-is" do
exception = ExceptionWithDetailedMessageButNoHighlight.new("Обичам те\n大好き")
expect(exception.detailed_message.encoding).to be(Encoding::UTF_8)

Bugsnag.notify(exception)

expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)
expect(exception["message"]).to eq("detail about 'Обичам те\n大好き'")
}
end

it "handles UTF-16 strings" do
exception = ExceptionWithDetailedMessageReturningEncodedString.new("Обичам те\n大好き", Encoding::UTF_16)
expect(exception.detailed_message.encoding).to be(Encoding::UTF_16)

Bugsnag.notify(exception)

expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)

# the exception message is converted to UTF-8 by the Cleaner
expect(exception["message"]).to eq("abc Обичам те\n大好き xyz")
}
end

it "handles Shift JIS strings" do
exception = ExceptionWithDetailedMessageReturningEncodedString.new("大好き\n大好き", Encoding::Shift_JIS)
expect(exception.detailed_message.encoding).to be(Encoding::Shift_JIS)

Bugsnag.notify(exception)

expect(Bugsnag).to have_sent_notification{ |payload, headers|
exception = get_exception_from_payload(payload)

# the exception message is converted to UTF-8 by the Cleaner
expect(exception["message"]).to eq("abc 大好き\n大好き xyz")
}
end
end

it "supports unix-style paths in backtraces" do
Expand Down

0 comments on commit 27beed6

Please sign in to comment.