Skip to content

Commit

Permalink
fix: Broken escaped unicode crashes JSON parser (rubycdp#452)
Browse files Browse the repository at this point in the history
Assigning broken unicode to a node directly from JS can lead to `JSON::ParserError: incomplete surrogate pair at ...` error. We try to unescape unicode code points and replace invalid ones with `?` char now. If still after that JSON cannot parse the string, we raise error. That's anyways the best we can do, we can't just skip CDP message.
  • Loading branch information
route authored Mar 19, 2024
1 parent 5271866 commit 842d2ea
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
13 changes: 12 additions & 1 deletion lib/ferrum/client/web_socket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ def on_open(_event)
end

def on_message(event)
data = JSON.parse(event.data)
data = begin
JSON.parse(event.data)
rescue JSON::ParserError
unescaped = unescape_unicode(event.data)
.encode("UTF-8", "UTF-8", undef: :replace, invalid: :replace, replace: "?")
JSON.parse(unescaped)
end

@messages.push(data)

output = event.data
Expand Down Expand Up @@ -100,6 +107,10 @@ def start
@messages.close
end
end

def unescape_unicode(value)
value.gsub(/\\u([\da-fA-F]{4})/) { |_| [::Regexp.last_match(1)].pack("H*").unpack("n*").pack("U*") }
end
end
end
end
21 changes: 21 additions & 0 deletions spec/node_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,27 @@
expect(el.text).to eq("FooBar")
end

it "works with valid utf8" do
browser.go_to("/unicode")
el = browser.at_css("#valid")

expect(el.text).to eq("Havregrynskake med marengs og nøtter 😍 såå god!")
end

it "works with invalid utf8" do
browser.go_to("/unicode")
el = browser.at_css("#invalid")

expect(el.text).to eq("Havregrynskake med marengs og nøtter ???")
end

it "works with curly utf8" do
browser.go_to("/unicode")
el = browser.at_css("#curly")

expect(el.text).to eq("😀 and ☀")
end

context "SVG tests" do
before do
browser.go_to("/ferrum/svg_test")
Expand Down
4 changes: 4 additions & 0 deletions spec/support/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ def initialize(something, message)
send_file("attachment.pdf")
end

get "/unicode" do
File.read("#{FERRUM_VIEWS}/unicode.html")
end

get "/:view" do |view|
erb view.to_sym, locals: { referrer: request.referrer }
end
Expand Down
19 changes: 19 additions & 0 deletions spec/support/views/unicode.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<body>
<p>
<span id="valid"></span>
</p>
<p>
<span id="invalid"></span>
</p>
<p>
<span id="curly"></span>
</p>
<script>
document.getElementById('invalid').innerHTML = "Havregrynskake med marengs og n\u00f8tter \ud83d"
document.getElementById('valid').innerHTML = "Havregrynskake med marengs og nøtter \ud83d\ude0d såå god!"
document.getElementById('curly').innerHTML = "\u{1F600} and \u{2600}"
</script>
</body>
</html>

0 comments on commit 842d2ea

Please sign in to comment.