nebari-dev / jhub-apps

Application creator and general launcher for JupyterHub
https://jhub-apps.nebari.dev/
BSD 3-Clause "New" or "Revised" License
27 stars 12 forks source link

[ENH] - enhanced prefix relocation support for applications #524

Open mcg1969 opened 1 week ago

mcg1969 commented 1 week ago

Feature description

Many web applications are not relocatable; that is, they assume they are deployed at the root path of a URL. Many times this is the fault of developers; in some cases, the particular app framework they're building makes it difficult.

I've developed an approach to solving this problem that we could potentially share with jhub-apps that sits in the proxy layer between the network and the application that rewrites URLs supporting relocation.

The implementation I've worked on uses OpenResty. Here is an example of how this is implemented. In this implementation, the prefix is fixed to be /__deployment/, but of course this could be parametrized. It actually edits the body content inline for HTML, CSS, and JS, looking for absolute local URLs and inserting the prefix where it finds them.

Is this foolproof? No. Is it something that should be on all the time? No. Does it work? Better than you might expect.

It would be great to offer this as an option in jhub_apps to support applications that haven't been written to support relocation to subpaths. I am happy to do some work here to make this happen if someone can help identify where it ought to go.

local buf = ngx.ctx.buffered or ""
buf = buf .. ngx.arg[1]
if ngx.arg[2] then
    --- rewrite absolute internal links so they have the prefix
    local ctype = ngx.header.content_type
    local repl = "%1/__deployment/%2"
    if ctype == "text/html" then
        buf = buf:gsub("(href=['\"])/([^/])", repl)
        buf = buf:gsub( "(src=['\"])/([^/])", repl)
    elseif ctype == "text/css" then
        buf = buf:gsub("(@import +['\"])/([^/])", repl)
        buf = buf:gsub(   "(url[(]['\"])/([^/])", repl)
    elseif ctype == "application/javascript" or ctype == "text/javascript" then
        buf = buf:gsub("(import .* from +['\"`])/([^/])", repl)
    end
    ngx.arg[1] = buf
else
    ngx.ctx.buffered = buf
    ngx.arg[1] = ''
end

Value and/or benefit

Improved application support

Anything else?

No response