Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### 0.4.1 (Next)

* [#8](https://github.com/dblock/ruby-link-checker/issues/8): Added `protocol` configuration option to `LinkChecker::Async::HTTP` to force HTTP/1 or HTTP/2 - [@dblock](https://github.com/dblock), [@Copilot](https://github.com/Copilot).
* Your contribution here.

### 0.4.0 (2026/8/17)
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ LinkChecker::Async::HTTP.configure do |config|
end
```

You can also force a specific HTTP protocol version, `:http1` or `:http2`, per instance or globally. By default, `async-http` negotiates the protocol version with the server.

```ruby
LinkChecker::Async::HTTP.configure do |config|
config.protocol = :http2
end
```

#### [LinkChecker::Net::HTTP](lib/ruby-link-checker/net/http/checker.rb)

Slow, sequential checker.
Expand Down
17 changes: 16 additions & 1 deletion lib/ruby-link-checker/async/http/checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,28 @@ def _queue(&block)
def _client_for(uri)
key = [uri.scheme, uri.host, uri.port]
@clients[key] ||= begin
endpoint = ::Async::HTTP::Endpoint.parse(uri.to_s, timeout: open_timeout)
endpoint = ::Async::HTTP::Endpoint.parse(uri.to_s, timeout: open_timeout, **_endpoint_options)
::Async::HTTP::Client.new(endpoint)
end
end

private

# Maps the configured protocol (:http1 or :http2) to the
# corresponding async-http protocol implementation.
def _endpoint_options
case protocol
when :http1
{ protocol: ::Async::HTTP::Protocol::HTTP1 }
when :http2
{ protocol: ::Async::HTTP::Protocol::HTTP2 }
when nil
{}
else
raise ArgumentError, "Unsupported protocol: #{protocol.inspect}, expected :http1 or :http2"
end
end

def _flush!
queue = @queue
@queue = []
Expand Down
2 changes: 2 additions & 0 deletions lib/ruby-link-checker/async/http/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ module Config
ATTRIBUTES = %i[
read_timeout
open_timeout
protocol
].freeze

attr_accessor(*Config::ATTRIBUTES)

def reset
self.read_timeout = nil
self.open_timeout = nil
self.protocol = nil
end
end

Expand Down
47 changes: 47 additions & 0 deletions spec/ruby-link-checker/async/http/checker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,53 @@ def check(url, options = {})
end
end

context 'with a protocol option', vcr: { cassette_name: '200' } do
before do
LinkChecker::Async::HTTP.configure do |config|
config.protocol = protocol
end
expect(Async::HTTP::Endpoint).to receive(:parse).with(
URI(url).to_s,
hash_including(protocol: expected_protocol)
).and_call_original
end

include_context 'with url'

context 'http1' do
let(:protocol) { :http1 }
let(:expected_protocol) { Async::HTTP::Protocol::HTTP1 }

it 'creates requests using HTTP/1' do
expect(result.success?).to be true
end
end

context 'http2' do
let(:protocol) { :http2 }
let(:expected_protocol) { Async::HTTP::Protocol::HTTP2 }

it 'creates requests using HTTP/2' do
expect(result.success?).to be true
end
end
end

context 'with an unsupported protocol option' do
before do
LinkChecker::Async::HTTP.configure do |config|
config.protocol = :http3
end
end

include_context 'with url'

it 'raises an ArgumentError' do
expect(result.error?).to be true
expect(result.error.message).to eq('Unsupported protocol: :http3, expected :http1 or :http2')
end
end

context 'timeout' do
before do
stub_request(:get, 'https://www.example.org/').to_timeout
Expand Down
Loading