Carrierwave 使用時にNoMethodError: undefined method `closed?' for nil:NilClass が発生した

## tl;dr
`ssrf_filter` が 1.1.0 以上の場合にエラーになるので Gemfile に以下を追加し `bundle install`、もしくは `bundle update ssrf_filter` を実行する。

```ruby:Gemfile
gem 'ssrf_filter', '1.0.8'
```

## デバッグ
ある時 `carrierwave` の `remote_*_url=` メソッドを使用時にこのエラーに遭遇しました。

```ruby
Medium.create!(remote_file_url: "https://mgre.co.jp/wp-content/themes/lanchester2017/assets/img/common/noimage1200x630.png")
NoMethodError: undefined method `closed?' for nil:NilClass
```

環境は ruby 3.0.1、rails 6.1.7、carrierwave 2.2.2 です。

モデルやアップローダーは以下です。一部省略していますが特別なところはありません。

```mysql
mysql> desc media;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| file       | varchar(255) | NO   |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
```

```ruby
class Medium < ApplicationRecord
  mount_uploader :file, MediumUploader
end
```

```ruby
class MediumUploader < CarrierWave::Uploader::Base
  process resize_to_limit: [750, 750]
end
```

ちなみに正確なエラーログは以下です。`Net::HTTP` が関係するエラーのようです。

```terminal
NoMethodError: undefined method `closed?' for nil:NilClass
from /Users/kurashita/.rbenv/versions/3.0.1/lib/ruby/3.0.0/net/http/response.rb:340:in `stream_check'
```

エラーログが少ないので `remote_*_url` メソッドのソースコードを直接確認していきます。
メソッドの定義箇所は以下のように調べられます。

```ruby
pry(main)> Medium.new.method(:remote_file_url=).source_location
=> ["/Users/kurashita/work/MGRe/MGRe/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.2/lib/carrierwave/orm/activerecord.rb", 18]
```

ソースを確認すると以下のようになっています。

```ruby:/Users/kurashita/work/MGRe/MGRe/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.2/lib/carrierwave/orm/activerecord.rb
require 'active_record'
require 'carrierwave/validations/active_model'

module CarrierWave
  module ActiveRecord

    include CarrierWave::Mount

    def mount_uploader(column, uploader=nil, options={}, &block)
      super

      mod = Module.new
      prepend mod
      mod.class_eval <<-RUBY, __FILE__, __LINE__+1
        def remote_#{column}_url=(url)
          column = _mounter(:#{column}).serialization_column
          __send__(:"\#{column}_will_change!")
          super
        end
      RUBY
    end
  ...
  end
end
```

処理の内容的にはほぼ `super` しているだけなのでオーバーライドされているメソッドを見ていきます。
オーバーライド元のメソッドは以下のように調べることが出来ます。

```ruby
pry(main)> Medium.new.method(:remote_file_url=).super_method.source_location
=> ["/Users/kurashita/work/MGRe/MGRe/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.2/lib/carrierwave/mount.rb", 165]
```

```ruby
module CarrierWave
  module Mount

    def mount_uploader(column, uploader=nil, options={}, &block)
      mount_base(column, uploader, options, &block)

      mod = Module.new
      include mod
      mod.class_eval <<-RUBY, __FILE__, __LINE__+1
        ...
        def remote_#{column}_url=(url)
          _mounter(:#{column}).remote_urls = [url]
        end
        ...
      RUBY
    end
  end
end
```

`_mounter(:#{column}).remote_urls=` メソッドを呼んでいるので例によってソースを調べていきます。
これを何度か繰り返すので途中割愛し、最終的なメソッドを見つけます。
最終的には以下の `download` メソッドに行き着きます。

```ruby:/Users/kurashita/work/MGRe/MGRe/vendor/bundle/ruby/3.0.0/gems/carrierwave-2.2.2/lib/carrierwave/downloader/base.rb
require 'open-uri'
require 'ssrf_filter'
require 'addressable'
require 'carrierwave/downloader/remote_file'

module CarrierWave
  module Downloader
    class Base
      attr_reader :uploader
　　　　　　　　　　　　...
      def download(url, remote_headers = {})
        headers = remote_headers.
          reverse_merge('User-Agent' => "CarrierWave/#{CarrierWave::VERSION}")
        uri = process_uri(url.to_s)
        begin
          if skip_ssrf_protection?(uri)
            response = OpenURI.open_uri(process_uri(url.to_s), headers)
          else
            request = nil
            response = SsrfFilter.get(uri, headers: headers) do |req|
              request = req
            end
            response.uri = request.uri
            response.value
          end
        rescue StandardError => e
          raise CarrierWave::DownloadError, "could not download file: #{e.message}"
        end
        CarrierWave::Downloader::RemoteFile.new(response)
      end
      ...
    end
  end
end
```

ここまで来て `SsrfFilter` が出てきました。
`ssrf_filter` では少し前に 1.0.8 から 1.1.0 のバージョンアップが行われているため、以下のどこかが影響している可能性があります。
https://github.com/arkadiyt/ssrf_filter/compare/1.0.8..1.1.0

ただ、今回は急ぎだったため以下のようにバージョンを落として対応しました。

```ruby:Gemfile
gem 'ssrf_filter', '1.0.8'
```