From e62d61abc1297620501103d5c7aea9df3a2e95bc Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 5 Mar 2023 00:55:27 +0100 Subject: [PATCH] Proxy: de-duplicate the code that copies headers --- src/invidious.cr | 4 +- src/invidious/routes/images.cr | 60 +++++-------------------- src/invidious/routes/video_playback.cr | 21 ++------- src/invidious/yt_backend/media_proxy.cr | 38 ++++++++++++++++ 4 files changed, 53 insertions(+), 70 deletions(-) create mode 100644 src/invidious/yt_backend/media_proxy.cr diff --git a/src/invidious.cr b/src/invidious.cr index d4f8e0fb..a6f12ba6 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -71,9 +71,7 @@ CHARS_SAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345 TEST_IDS = {"AgbeGFYluEA", "BaW_jenozKc", "a9LDPn-MO4I", "ddFvjfvPnqk", "iqKdEhx-dD4"} MAX_ITEMS_PER_PAGE = 1500 -REQUEST_HEADERS_WHITELIST = {"accept", "accept-encoding", "cache-control", "content-length", "if-none-match", "range"} -RESPONSE_HEADERS_BLACKLIST = {"access-control-allow-origin", "alt-svc", "server"} -HTTP_CHUNK_SIZE = 10485760 # ~10MB +HTTP_CHUNK_SIZE = 10485760 # ~10MB CURRENT_BRANCH = {{ "#{`git branch | sed -n '/* /s///p'`.strip}" }} CURRENT_COMMIT = {{ "#{`git rev-list HEAD --max-count=1 --abbrev-commit`.strip}" }} diff --git a/src/invidious/routes/images.cr b/src/invidious/routes/images.cr index d6f6d3db..db7359b1 100644 --- a/src/invidious/routes/images.cr +++ b/src/invidious/routes/images.cr @@ -6,22 +6,14 @@ module Invidious::Routes::Images headers = HTTP::Headers.new headers[":authority"] = "yt3.ggpht.com" if CONFIG.use_quic - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end + MediaProxy.copy_request_headers(from: env.request.headers, to: headers) # We're encapsulating this into a proc in order to easily reuse this # portion of the code for each request block below. request_proc = ->(response : HTTP::Client::Response) { env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end + MediaProxy.copy_response_headers(from: response.headers, to: env.response.headers) env.response.headers["Access-Control-Allow-Origin"] = "*" if response.status_code >= 300 @@ -64,20 +56,12 @@ module Invidious::Routes::Images headers = HTTP::Headers.new headers[":authority"] = "#{authority}.ytimg.com" if CONFIG.use_quic - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end + MediaProxy.copy_request_headers(from: env.request.headers, to: headers) request_proc = ->(response : HTTP::Client::Response) { env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end + MediaProxy.copy_response_headers(from: response.headers, to: env.response.headers) env.response.headers["Connection"] = "close" env.response.headers["Access-Control-Allow-Origin"] = "*" @@ -112,20 +96,12 @@ module Invidious::Routes::Images headers = HTTP::Headers.new headers[":authority"] = "i9.ytimg.com" if CONFIG.use_quic - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end + MediaProxy.copy_request_headers(from: env.request.headers, to: headers) request_proc = ->(response : HTTP::Client::Response) { env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end + MediaProxy.copy_response_headers(from: response.headers, to: env.response.headers) env.response.headers["Access-Control-Allow-Origin"] = "*" if response.status_code >= 300 && response.status_code != 404 @@ -152,21 +128,13 @@ module Invidious::Routes::Images def self.yts_image(env) headers = HTTP::Headers.new - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end + MediaProxy.copy_request_headers(from: env.request.headers, to: headers) begin YT_POOL.client &.get(env.request.resource, headers) do |response| env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end + MediaProxy.copy_response_headers(from: response.headers, to: env.response.headers) env.response.headers["Access-Control-Allow-Origin"] = "*" if response.status_code >= 300 && response.status_code != 404 @@ -209,20 +177,12 @@ module Invidious::Routes::Images url = "/vi/#{id}/#{name}" - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end + MediaProxy.copy_request_headers(from: env.request.headers, to: headers) request_proc = ->(response : HTTP::Client::Response) { env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end + MediaProxy.copy_response_headers(from: response.headers, to: env.response.headers) env.response.headers["Access-Control-Allow-Origin"] = "*" if response.status_code >= 300 && response.status_code != 404 diff --git a/src/invidious/routes/video_playback.cr b/src/invidious/routes/video_playback.cr index 1e932d11..63559ab5 100644 --- a/src/invidious/routes/video_playback.cr +++ b/src/invidious/routes/video_playback.cr @@ -29,11 +29,7 @@ module Invidious::Routes::VideoPlayback url = "/videoplayback?#{query_params}" headers = HTTP::Headers.new - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end + MediaProxy.copy_request_headers(from: env.request.headers, to: headers) # See: https://github.com/iv-org/invidious/issues/3302 range_header = env.request.headers["Range"]? @@ -92,12 +88,7 @@ module Invidious::Routes::VideoPlayback begin client.get(url, headers) do |resp| - resp.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end - + MediaProxy.copy_response_headers(from: resp.headers, to: env.response.headers) env.response.headers["Access-Control-Allow-Origin"] = "*" if location = resp.headers["Location"]? @@ -150,12 +141,8 @@ module Invidious::Routes::VideoPlayback env.response.status_code = resp.status_code end - resp.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) && key.downcase != "content-range" - env.response.headers[key] = value - end - end - + MediaProxy.copy_response_headers(from: resp.headers, to: env.response.headers) + env.response.headers.delete("Content-Range") # Important! env.response.headers["Access-Control-Allow-Origin"] = "*" if location = resp.headers["Location"]? diff --git a/src/invidious/yt_backend/media_proxy.cr b/src/invidious/yt_backend/media_proxy.cr new file mode 100644 index 00000000..3eebb3ad --- /dev/null +++ b/src/invidious/yt_backend/media_proxy.cr @@ -0,0 +1,38 @@ +module Invidious::MediaProxy + extend self + + # ------------------- + # Constants + # ------------------- + + private REQUEST_HEADERS_WHITELIST = { + "accept", "accept-encoding", "cache-control", + "content-length", "if-none-match", "range", + } + + private RESPONSE_HEADERS_BLACKLIST = { + "access-control-allow-origin", "alt-svc", "server", + } + + # ------------------- + # Headers functions + # ------------------- + + # Copy only the selected headers from the client to youtube servers + # (in general, from `env.request` to a temporary `HTTP::Headers` object). + def copy_request_headers(*, from : HTTP::Headers, to : HTTP::Headers) + REQUEST_HEADERS_WHITELIST.each do |header| + to[header] = from[header] if from[header]? + end + end + + # Copy only the selected headers from youtube servers to the client + # (generally, from a response block to `env.response`). + def copy_response_headers(*, from : HTTP::Headers, to : HTTP::Headers) + from.each do |key, value| + if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) + to[key] = value + end + end + end +end