Skip to content

Commit

Permalink
brotli is an optional dependency
Browse files Browse the repository at this point in the history
- move dev deps to the Gemfile
- brotli is not a dev dep for jruby (which it doesn't support)
- test how brotli responses are handled when Brotli is not loaded
  • Loading branch information
flavorjones committed Jul 28, 2024
1 parent 45c2754 commit b6f0795
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 15 deletions.
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
source "https://rubygems.org"

gemspec

gem "minitest", "~> 5.14"
gem "rake", "~> 13.0"
gem "rdoc", "~> 6.3"
gem "rubocop", "~> 1.12"
gem "brotli", ">= 0.5" unless RUBY_PLATFORM == "java"
21 changes: 15 additions & 6 deletions lib/mechanize/http/agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
require 'tempfile'
require 'net/ntlm'
require 'webrobots'
require 'brotli'

##
# An HTTP (and local disk access) user agent. This class is an implementation
Expand Down Expand Up @@ -498,14 +497,24 @@ def content_encoding_inflate body_io

##
# Decodes a Brotli-encoded +body_io+
#
# Although Mechanize will never request a Brotli-encoded response via `accept-encoding`, buggy
# servers may return brotli-encoded responses anyway. Let's try to handle that case if the Brotli
# gem is loaded.

def content_encoding_brotli(body_io)
log.debug('deflate brotly body') if log
log.debug('deflate brotli body') if log

unless defined?(::Brotli)
raise Mechanize::Error, "cannot deflate brotli-encoded response. Please install and require the 'brotli' gem."
end

return StringIO.new(Brotli.inflate(body_io.read))
rescue Brotli::Error
log.error('unable to brotli-inflate response') if log
raise Mechanize::Error, "could not inflate brotli-encoded response"
begin
return StringIO.new(Brotli.inflate(body_io.read))
rescue Brotli::Error
log.error("unable to brotli-inflate response") if log
raise Mechanize::Error, "error inflating brotli-encoded response."
end
ensure
body_io.close
end
Expand Down
6 changes: 0 additions & 6 deletions mechanize.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency("http-cookie", ">= 1.0.3", "~> 1.0")
spec.add_runtime_dependency("mime-types", "~> 3.0")
spec.add_runtime_dependency("net-http-digest_auth", ">= 1.4.1", "~> 1.4")
spec.add_runtime_dependency("brotli", ">= 0.5")

# careful! some folks are relying on older versions of net-http-persistent
# - see the socks proxy patch in use at #507 and #464
Expand All @@ -72,9 +71,4 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency("rubyntlm", ">= 0.6.3", "~> 0.6")
spec.add_runtime_dependency("base64") # removed from bundled gems in 3.4, and needed by rubyntlm (which doesn't declare this dependency)
spec.add_runtime_dependency("nkf") # removed from bundled gems in 3.4

spec.add_development_dependency("minitest", "~> 5.14")
spec.add_development_dependency("rake", "~> 13.0")
spec.add_development_dependency("rdoc", "~> 6.3")
spec.add_development_dependency("rubocop", "~> 1.12")
end
25 changes: 22 additions & 3 deletions test/test_mechanize_http_agent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# frozen_string_literal: true

require 'mechanize/test_case'
require "brotli" unless RUBY_PLATFORM == "java"

class TestMechanizeHttpAgent < Mechanize::TestCase

Expand Down Expand Up @@ -924,7 +925,23 @@ def @res.content_length() nil end
assert_equal 'part', body.read
end

def test_response_content_encoding_br
def test_response_content_encoding_brotli_when_brotli_not_loaded
skip("only test this on jruby which doesn't have brotli support") unless RUBY_ENGINE == 'jruby'

@res.instance_variable_set :@header, 'content-encoding' => %w[br]
body_io = StringIO.new("content doesn't matter for this test")

e = assert_raises(Mechanize::Error) do
@agent.response_content_encoding(@res, body_io)
end
assert_includes(e.message, "cannot deflate brotli-encoded response")

assert(body_io.closed?)
end

def test_response_content_encoding_brotli
skip("jruby does not have brotli support") if RUBY_ENGINE == 'jruby'

@res.instance_variable_set :@header, 'content-encoding' => %w[br]
body_io = StringIO.new(Brotli.deflate("this is compressed by brotli"))

Expand All @@ -934,14 +951,16 @@ def test_response_content_encoding_br
assert(body_io.closed?)
end

def test_response_content_encoding_br_corrupt
def test_response_content_encoding_brotli_corrupt
skip("jruby does not have brotli support") if RUBY_ENGINE == 'jruby'

@res.instance_variable_set :@header, 'content-encoding' => %w[br]
body_io = StringIO.new("not a brotli payload")

e = assert_raises(Mechanize::Error) do
@agent.response_content_encoding(@res, body_io)
end
assert_includes(e.message, "could not inflate brotli-encoded response")
assert_includes(e.message, "error inflating brotli-encoded response")
assert_includes(e.cause.message, "ERROR_FORMAT_PADDING_2")

assert(body_io.closed?)
Expand Down

0 comments on commit b6f0795

Please sign in to comment.