summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamantaz Fox <coding@samantaz.fr>2024-10-30 13:46:49 +0100
committerSamantaz Fox <coding@samantaz.fr>2024-10-30 13:46:49 +0100
commitf326bcf8db2311c3d57d928a1f9722ce5c036150 (patch)
tree651e32855b234a7e385a5566dc5eac459d71af5b
parentd8b893e9ad456598a3e127cec578dd3355141578 (diff)
parent6b7e7301009e1a9fc2b536bd8d8de04fb8e22ec0 (diff)
downloadinvidious-f326bcf8db2311c3d57d928a1f9722ce5c036150.tar.gz
invidious-f326bcf8db2311c3d57d928a1f9722ce5c036150.tar.bz2
invidious-f326bcf8db2311c3d57d928a1f9722ce5c036150.zip
Add support for using Invidious through a HTTP Proxy (#4270)
Partially addresses issue 301
-rw-r--r--config/config.example.yml11
-rw-r--r--shard.lock8
-rw-r--r--shard.yml3
-rw-r--r--src/invidious.cr1
-rw-r--r--src/invidious/config.cr11
-rw-r--r--src/invidious/helpers/crystal_class_overrides.cr34
-rw-r--r--src/invidious/yt_backend/connection_pool.cr19
7 files changed, 84 insertions, 3 deletions
diff --git a/config/config.example.yml b/config/config.example.yml
index e9eebfde..759b81e0 100644
--- a/config/config.example.yml
+++ b/config/config.example.yml
@@ -173,6 +173,17 @@ https_only: false
##
#force_resolve:
+##
+## Configuration for using a HTTP proxy
+##
+## If unset, then no HTTP proxy will be used.
+##
+http_proxy:
+ user:
+ password:
+ host:
+ port:
+
##
## Use Innertube's transcripts API instead of timedtext for closed captions
diff --git a/shard.lock b/shard.lock
index 397bd8bc..50e64c64 100644
--- a/shard.lock
+++ b/shard.lock
@@ -10,7 +10,7 @@ shards:
backtracer:
git: https://github.com/sija/backtracer.cr.git
- version: 1.2.1
+ version: 1.2.2
db:
git: https://github.com/crystal-lang/crystal-db.git
@@ -20,6 +20,10 @@ shards:
git: https://github.com/crystal-loot/exception_page.git
version: 0.2.2
+ http_proxy:
+ git: https://github.com/mamantoha/http_proxy.git
+ version: 0.10.3
+
kemal:
git: https://github.com/kemalcr/kemal.git
version: 1.1.2
@@ -42,7 +46,7 @@ shards:
spectator:
git: https://github.com/icy-arctic-fox/spectator.git
- version: 0.10.4
+ version: 0.10.6
sqlite3:
git: https://github.com/crystal-lang/crystal-sqlite3.git
diff --git a/shard.yml b/shard.yml
index 367f7c73..14c2a84e 100644
--- a/shard.yml
+++ b/shard.yml
@@ -28,6 +28,9 @@ dependencies:
athena-negotiation:
github: athena-framework/negotiation
version: ~> 0.1.1
+ http_proxy:
+ github: mamantoha/http_proxy
+ version: ~> 0.10.3
development_dependencies:
spectator:
diff --git a/src/invidious.cr b/src/invidious.cr
index 63f2a9cc..ccb70ba5 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -23,6 +23,7 @@ require "kilt"
require "./ext/kemal_content_for.cr"
require "./ext/kemal_static_file_handler.cr"
+require "http_proxy"
require "athena-negotiation"
require "openssl/hmac"
require "option_parser"
diff --git a/src/invidious/config.cr b/src/invidious/config.cr
index a097b7f1..c1766fbb 100644
--- a/src/invidious/config.cr
+++ b/src/invidious/config.cr
@@ -55,6 +55,15 @@ struct ConfigPreferences
end
end
+struct HTTPProxyConfig
+ include YAML::Serializable
+
+ property user : String
+ property password : String
+ property host : String
+ property port : Int32
+end
+
class Config
include YAML::Serializable
@@ -129,6 +138,8 @@ class Config
property host_binding : String = "0.0.0.0"
# Pool size for HTTP requests to youtube.com and ytimg.com (each domain has a separate pool of `pool_size`)
property pool_size : Int32 = 100
+ # HTTP Proxy configuration
+ property http_proxy : HTTPProxyConfig? = nil
# Use Innertube's transcripts API instead of timedtext for closed captions
property use_innertube_for_captions : Bool = false
diff --git a/src/invidious/helpers/crystal_class_overrides.cr b/src/invidious/helpers/crystal_class_overrides.cr
index fec3f62c..3040d7a0 100644
--- a/src/invidious/helpers/crystal_class_overrides.cr
+++ b/src/invidious/helpers/crystal_class_overrides.cr
@@ -18,6 +18,40 @@ end
class HTTP::Client
property family : Socket::Family = Socket::Family::UNSPEC
+ # Override stdlib to automatically initialize proxy if configured
+ #
+ # Accurate as of crystal 1.12.1
+
+ def initialize(@host : String, port = nil, tls : TLSContext = nil)
+ check_host_only(@host)
+
+ {% if flag?(:without_openssl) %}
+ if tls
+ raise "HTTP::Client TLS is disabled because `-D without_openssl` was passed at compile time"
+ end
+ @tls = nil
+ {% else %}
+ @tls = case tls
+ when true
+ OpenSSL::SSL::Context::Client.new
+ when OpenSSL::SSL::Context::Client
+ tls
+ when false, nil
+ nil
+ end
+ {% end %}
+
+ @port = (port || (@tls ? 443 : 80)).to_i
+
+ self.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
+ end
+
+ def initialize(@io : IO, @host = "", @port = 80)
+ @reconnect = false
+
+ self.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
+ end
+
private def io
io = @io
return io if io
diff --git a/src/invidious/yt_backend/connection_pool.cr b/src/invidious/yt_backend/connection_pool.cr
index ca612083..70b15f26 100644
--- a/src/invidious/yt_backend/connection_pool.cr
+++ b/src/invidious/yt_backend/connection_pool.cr
@@ -26,12 +26,16 @@ struct YoutubeConnectionPool
def client(&)
conn = pool.checkout
+ # Proxy needs to be reinstated every time we get a client from the pool
+ conn.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
+
begin
response = yield conn
rescue ex
conn.close
- conn = HTTP::Client.new(url)
+ conn = HTTP::Client.new(url)
+ conn.proxy = make_configured_http_proxy_client() if CONFIG.http_proxy
conn.family = CONFIG.force_resolve
conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC
conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
@@ -77,3 +81,16 @@ def make_client(url : URI, region = nil, force_resolve : Bool = false, &)
client.close
end
end
+
+def make_configured_http_proxy_client
+ # This method is only called when configuration for an HTTP proxy are set
+ config_proxy = CONFIG.http_proxy.not_nil!
+
+ return HTTP::Proxy::Client.new(
+ config_proxy.host,
+ config_proxy.port,
+
+ username: config_proxy.user,
+ password: config_proxy.password,
+ )
+end