mirror of
https://github.com/mudler/LocalAI.git
synced 2026-04-25 20:49:42 -05:00
8cc2d01caa
Makes the web app honour the `X-Forwarded-Prefix` HTTP request header that may be sent by a reverse-proxy in order to inform the app that its public routes contain a path prefix. For instance this allows to serve the webapp via a reverse-proxy/ingress controller under a path prefix/sub path such as e.g. `/localai/` while still being able to use the regular LocalAI routes/paths without prefix when directly connecting to the LocalAI server. Changes: * Add new `StripPathPrefix` middleware to strip the path prefix (provided with the `X-Forwarded-Prefix` HTTP request header) from the request path prior to matching the HTTP route. * Add a `BaseURL` utility function to build the base URL, honouring the `X-Forwarded-Prefix` HTTP request header. * Generate the derived base URL into the HTML (`head.html` template) as `<base/>` tag. * Make all webapp-internal URLs (within HTML+JS) relative in order to make the browser resolve them against the `<base/>` URL specified within each HTML page's header. * Make font URLs within the CSS files relative to the CSS file. * Generate redirect location URLs using the new `BaseURL` function. * Use the new `BaseURL` function to generate absolute URLs within gallery JSON responses. Closes #3095 TL;DR: The header-based approach allows to move the path prefix configuration concern completely to the reverse-proxy/ingress as opposed to having to align the path prefix configuration between LocalAI, the reverse-proxy and potentially other internal LocalAI clients. The gofiber swagger handler already supports path prefixes this way, see https://github.com/gofiber/swagger/blob/e2d9e9916d8809e8b23c4365f8acfbbd8a71c4cd/swagger.go#L79 Signed-off-by: Max Goltzsche <max.goltzsche@gmail.com>
49 lines
983 B
Go
49 lines
983 B
Go
package utils
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestBaseURL(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
prefix string
|
|
expectURL string
|
|
}{
|
|
{
|
|
name: "without prefix",
|
|
prefix: "/",
|
|
expectURL: "http://example.com/",
|
|
},
|
|
{
|
|
name: "with prefix",
|
|
prefix: "/myprefix/",
|
|
expectURL: "http://example.com/myprefix/",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
app := fiber.New()
|
|
actualURL := ""
|
|
|
|
app.Get(tc.prefix+"hello/world", func(c *fiber.Ctx) error {
|
|
if tc.prefix != "/" {
|
|
c.Path("/hello/world")
|
|
}
|
|
actualURL = BaseURL(c)
|
|
return nil
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", tc.prefix+"hello/world", nil)
|
|
resp, err := app.Test(req, -1)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, resp.StatusCode, "response status code")
|
|
require.Equal(t, tc.expectURL, actualURL, "base URL")
|
|
})
|
|
}
|
|
}
|