Files
redux-scraper/app/controllers/admin/proxy_controller.rb

85 lines
2.5 KiB
Ruby

# typed: true
# frozen_string_literal: true
class Admin::ProxyController < ApplicationController
before_action :authenticate_user!
before_action :require_admin!
skip_before_action :verify_authenticity_token, only: %i[grafana prometheus]
def grafana
fullpath =
"http://grafana:3100#{request.fullpath.delete_prefix("/grafana")}"
proxy_response(fullpath, "/grafana")
end
def prometheus
fullpath = "http://prometheus:9090#{request.fullpath.delete_prefix("/prometheus")}"
proxy_response(fullpath, "/prometheus")
end
private
def require_admin!
unless current_user&.admin?
redirect_to root_path, alert: "You are not authorized to access this area"
end
end
def grafana_proxy_headers
{ "X-WEBAUTH-USER" => "admin" }.merge(proxy_headers)
end
def proxy_headers
{
"X-Forwarded-Host" => request.host_with_port,
"X-Forwarded-Proto" => request.ssl? ? "https" : "http",
"X-Forwarded-For" => request.remote_ip,
"Host" => request.host,
"Connection" => request.headers["Connection"],
"Upgrade" => request.headers["Upgrade"],
"Accept" => request.headers["Accept"],
"Cookie" => request.headers["Cookie"],
"Content-Type" => request.headers["Content-Type"],
"Content-Length" => request.headers["Content-Length"],
}.merge
end
def websocket_request?
request.headers["Connection"]&.include?("upgrade")
end
def proxy_response(fullpath, prefix)
method = request.method.downcase.to_s
if method == "post"
response = HTTP.headers(grafana_proxy_headers).send(method, fullpath, body: request.raw_post)
else
response = HTTP.headers(grafana_proxy_headers).send(method, fullpath)
end
headers = response.headers.to_h
# Handle redirects by rewriting the Location header
if response.code.in?([301, 302, 303, 307, 308]) &&
headers["Location"].present?
location = headers["Location"]
# Strip the host from absolute URLs
location = location.gsub(%r{^https?://[^/]+}, "")
# Add our prefix to relative URLs
location = "#{prefix}#{location}" if location.start_with?("/")
headers["Location"] = location
end
# Pass through the response with all headers
response_headers = headers.except("Content-Type")
render_args = {
body: response.body.to_s,
status: response.code,
content_type: headers["Content-Type"],
headers: response_headers,
}
render_args[:location] = headers["Location"] if headers["Location"]
render render_args
end
end