Created
April 26, 2022 09:52
-
-
Save doriantaylor/932defd722d922051d0efd43e9a7c68b to your computer and use it in GitHub Desktop.
script to use in rewrite map for aliased subdomains
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'time' | |
require 'pathname' | |
require 'uri' | |
NULL = 'NULL'.freeze | |
RECHECK = 5 # how many seconds to wait before stat() | |
class RewriteProxy | |
def initialize root, basename | |
@root = Pathname(root).expand_path.freeze | |
@dom = @root.to_s.split(?/).drop(1).reverse.join(?.).split(?.).freeze | |
@base = basename | |
@map = {} | |
end | |
# load the rewrite map into a hash | |
def load_map file | |
fh = file.is_a?(IO) ? file : (@root + file).open | |
out = {} | |
fh.readlines.each do |line| | |
# regex will empty the line | |
source, target = line.chomp.sub(/(?:^|\s+)#.*/, '').split(/\s+/) | |
# will be nil if the line is empty | |
out[source.freeze] ||= target.freeze if source and target | |
# (note we use ||= to get the first record, not the last one) | |
# warn "#{@base} -> #{target}" if source.empty? | |
end | |
out | |
end | |
# refresh the map file if necessary | |
def map_for host | |
# get the domain labels (yes that's what they're called) | |
labels = host.split(?.) | |
# warn (labels & @dom).inspect | |
# bail out unless the host matches the directory structure | |
return if (labels & @dom).empty? | |
# now we get the file | |
file = @root + (labels - @dom).join(?/) + @base | |
# nothing to do if this doesn't exist | |
return unless file.readable? | |
# warn file | |
# this is a handbrake from testing it every time | |
now = Time.now | |
map = @map[host] | |
# byeeee | |
return map[:data] if map and now - map[:checked] < RECHECK | |
# okay now we hit the file system | |
stat = file.stat | |
if !map or map[:mtime] < stat.mtime | |
# ensure that we initialize the object | |
map ||= @map[host] ||= {} | |
# populate the fields | |
map[:mtime] = stat.mtime | |
map[:data] = load_map file | |
# warn map[:data].size | |
end | |
# update the checked timestamp unconditionally | |
map[:checked] = now | |
# we return just the data | |
map[:data] | |
end | |
def handle_line line | |
begin | |
line = line.strip | |
line = 'https://' + line unless /^https?:\/\//i.match? line | |
uri = URI(line).normalize | |
rescue URI::Error | |
return NULL | |
end | |
# nothin' to do if there's nothin' to do | |
return NULL unless map = map_for(uri.host) | |
# try the raw request-uri, then just the path | |
out = map[uri.request_uri.delete_prefix ?/] || | |
map[uri.path.delete_prefix ?/] || NULL | |
# warn "#{@base}: #{uri} -> #{out}" | |
out | |
end | |
def run input = $stdin, output = $stdout | |
input.sync = true if input.respond_to? :sync= | |
output.sync = true if input.respond_to? :sync= | |
begin | |
while line = input.readline | |
output.puts handle_line line | |
end | |
rescue EOFError | |
# this does not need to whine when the server is restarted | |
exit | |
end | |
end | |
end | |
if __FILE__ == $0 | |
# this thing assumes you have a vhost alias that maps | |
# *.subdomain.rootdir.biz to .../rootdir.biz/subdomain/*, and each | |
# of these subdomains has a set of text rewrite maps. this program | |
# then loads and caches the rewrite maps (periodically stat()ing | |
# them to reload). you install it in apache like this: | |
# | |
# RewriteMap whatever "prg:/wherever/rewrite-proxy.rb rootdir mapfile" | |
# | |
# (usage: rewrite-proxy.rb rootdir mapfile) | |
RewriteProxy.new(*ARGV[0,2]).run | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment