Skip to content

Commit

Permalink
Fix crystal overrides (#2295)
Browse files Browse the repository at this point in the history
* 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
   crystal-lang/crystal#10965
   for more details about this issue).
  • Loading branch information
SamantazFox committed Aug 3, 2021
1 parent e9add69 commit 4b46313
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 51 deletions.
2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ dependencies:
github: iv-org/lsquic.cr
version: ~> 2.18.1-2

crystal: 1.0.0
crystal: ">= 1.0.0, < 2.0.0"

license: AGPLv3
70 changes: 70 additions & 0 deletions src/invidious/helpers/crystal_class_overrides.cr
Original file line number Diff line number Diff line change
@@ -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
50 changes: 0 additions & 50 deletions src/invidious/helpers/helpers.cr
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,6 @@ def check_table(db, table_name, struct_type = nil)
end
end

class PG::ResultSet
def field(index = @column_index)
@fields.not_nil![index]
end
end

def get_column_array(db, table_name)
column_array = [] of String
db.query("SELECT * FROM #{table_name} LIMIT 0") do |rs|
Expand Down Expand Up @@ -699,47 +693,3 @@ def proxy_file(response, env)
IO.copy response.body_io, env.response
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

0 comments on commit 4b46313

Please sign in to comment.