Fix crystal overrides (#2295)
* Move Crystal stdlib classes overrides to a separate file * Document known crystal overrides * Update crystal overrides for HTTP::Client socket * Update shard.yml to restrict crystal versions * Fix compilation error in Crystal 1.1.x (See https://github.com/crystal-lang/crystal/issues/10965 for more details about this issue).
This commit is contained in:
parent
e9add69e26
commit
4b46313e19
3 changed files with 71 additions and 51 deletions
|
@ -26,6 +26,6 @@ dependencies:
|
||||||
github: iv-org/lsquic.cr
|
github: iv-org/lsquic.cr
|
||||||
version: ~> 2.18.1-2
|
version: ~> 2.18.1-2
|
||||||
|
|
||||||
crystal: 1.0.0
|
crystal: ">= 1.0.0, < 2.0.0"
|
||||||
|
|
||||||
license: AGPLv3
|
license: AGPLv3
|
||||||
|
|
70
src/invidious/helpers/crystal_class_overrides.cr
Normal file
70
src/invidious/helpers/crystal_class_overrides.cr
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# Override of the TCPSocket and HTTP::Client classes in oder to allow an
|
||||||
|
# IP family to be selected for domains that resolve to both IPv4 and
|
||||||
|
# IPv6 addresses.
|
||||||
|
#
|
||||||
|
class TCPSocket
|
||||||
|
def initialize(host : String, port, dns_timeout = nil, connect_timeout = nil, family = Socket::Family::UNSPEC)
|
||||||
|
Addrinfo.tcp(host, port, timeout: dns_timeout, family: family) do |addrinfo|
|
||||||
|
super(addrinfo.family, addrinfo.type, addrinfo.protocol)
|
||||||
|
connect(addrinfo, timeout: connect_timeout) do |error|
|
||||||
|
close
|
||||||
|
error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# :ditto:
|
||||||
|
class HTTP::Client
|
||||||
|
property family : Socket::Family = Socket::Family::UNSPEC
|
||||||
|
|
||||||
|
private def io
|
||||||
|
io = @io
|
||||||
|
return io if io
|
||||||
|
unless @reconnect
|
||||||
|
raise "This HTTP::Client cannot be reconnected"
|
||||||
|
end
|
||||||
|
|
||||||
|
hostname = @host.starts_with?('[') && @host.ends_with?(']') ? @host[1..-2] : @host
|
||||||
|
io = TCPSocket.new hostname, @port, @dns_timeout, @connect_timeout, @family
|
||||||
|
io.read_timeout = @read_timeout if @read_timeout
|
||||||
|
io.write_timeout = @write_timeout if @write_timeout
|
||||||
|
io.sync = false
|
||||||
|
|
||||||
|
{% if !flag?(:without_openssl) %}
|
||||||
|
if tls = @tls
|
||||||
|
tcp_socket = io
|
||||||
|
begin
|
||||||
|
io = OpenSSL::SSL::Socket::Client.new(tcp_socket, context: tls, sync_close: true, hostname: @host)
|
||||||
|
rescue exc
|
||||||
|
# don't leak the TCP socket when the SSL connection failed
|
||||||
|
tcp_socket.close
|
||||||
|
raise exc
|
||||||
|
end
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
@io = io
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Mute the ClientError exception raised when a connection is flushed.
|
||||||
|
# This happends when the connection is unexpectedly closed by the client.
|
||||||
|
#
|
||||||
|
class HTTP::Server::Response
|
||||||
|
class Output
|
||||||
|
private def unbuffered_flush
|
||||||
|
@io.flush
|
||||||
|
rescue ex : IO::Error
|
||||||
|
unbuffered_close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO: Document this override
|
||||||
|
#
|
||||||
|
class PG::ResultSet
|
||||||
|
def field(index = @column_index)
|
||||||
|
@fields.not_nil![index]
|
||||||
|
end
|
||||||
|
end
|
|
@ -509,12 +509,6 @@ def check_table(db, table_name, struct_type = nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class PG::ResultSet
|
|
||||||
def field(index = @column_index)
|
|
||||||
@fields.not_nil![index]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_column_array(db, table_name)
|
def get_column_array(db, table_name)
|
||||||
column_array = [] of String
|
column_array = [] of String
|
||||||
db.query("SELECT * FROM #{table_name} LIMIT 0") do |rs|
|
db.query("SELECT * FROM #{table_name} LIMIT 0") do |rs|
|
||||||
|
@ -699,47 +693,3 @@ def proxy_file(response, env)
|
||||||
IO.copy response.body_io, env.response
|
IO.copy response.body_io, env.response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class HTTP::Server::Response
|
|
||||||
class Output
|
|
||||||
private def unbuffered_flush
|
|
||||||
@io.flush
|
|
||||||
rescue ex : IO::Error
|
|
||||||
unbuffered_close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class HTTP::Client
|
|
||||||
property family : Socket::Family = Socket::Family::UNSPEC
|
|
||||||
|
|
||||||
private def socket
|
|
||||||
socket = @socket
|
|
||||||
return socket if socket
|
|
||||||
|
|
||||||
hostname = @host.starts_with?('[') && @host.ends_with?(']') ? @host[1..-2] : @host
|
|
||||||
socket = TCPSocket.new hostname, @port, @dns_timeout, @connect_timeout, @family
|
|
||||||
socket.read_timeout = @read_timeout if @read_timeout
|
|
||||||
socket.sync = false
|
|
||||||
|
|
||||||
{% if !flag?(:without_openssl) %}
|
|
||||||
if tls = @tls
|
|
||||||
socket = OpenSSL::SSL::Socket::Client.new(socket, context: tls, sync_close: true, hostname: @host)
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
@socket = socket
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class TCPSocket
|
|
||||||
def initialize(host, port, dns_timeout = nil, connect_timeout = nil, family = Socket::Family::UNSPEC)
|
|
||||||
Addrinfo.tcp(host, port, timeout: dns_timeout, family: family) do |addrinfo|
|
|
||||||
super(addrinfo.family, addrinfo.type, addrinfo.protocol)
|
|
||||||
connect(addrinfo, timeout: connect_timeout) do |error|
|
|
||||||
close
|
|
||||||
error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
Loading…
Reference in a new issue