mirror of
https://github.com/mudler/LocalAI.git
synced 2026-06-25 00:59:28 -04:00
feat(http): honor explicit external base URL in BaseURL
When _external_base_url is set in the request context it dictates the origin (scheme+host+port); the proxy path prefix is still appended. Refs #10482 Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
@@ -55,6 +55,14 @@ func BasePathPrefix(c echo.Context) string {
|
||||
// The returned URL is guaranteed to end with `/`.
|
||||
// The method should be used in conjunction with the StripPathPrefix middleware.
|
||||
func BaseURL(c echo.Context) string {
|
||||
// An explicit external base URL (LOCALAI_BASE_URL) is authoritative for
|
||||
// the origin. The proxy-derived path prefix is still appended so a
|
||||
// reverse-proxy mount point keeps working. Trailing slashes are
|
||||
// normalized via BasePathPrefix, which always starts and ends with "/".
|
||||
if ext, ok := c.Get("_external_base_url").(string); ok && ext != "" {
|
||||
return strings.TrimRight(ext, "/") + BasePathPrefix(c)
|
||||
}
|
||||
|
||||
fwdProto, fwdHost := parseForwarded(c.Request().Header.Get("Forwarded"))
|
||||
|
||||
scheme := "http"
|
||||
|
||||
@@ -180,4 +180,51 @@ var _ = Describe("BaseURL", func() {
|
||||
Expect(actualURL).To(Equal("https://xfh.example/"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("explicit external base URL override", func() {
|
||||
It("uses the configured origin over conflicting forwarded headers", func() {
|
||||
app := echo.New()
|
||||
actualURL := ""
|
||||
app.GET("/x", func(c echo.Context) error {
|
||||
c.Set("_external_base_url", "https://192.168.0.13:34567")
|
||||
actualURL = BaseURL(c)
|
||||
return nil
|
||||
})
|
||||
req := httptest.NewRequest("GET", "/x", nil)
|
||||
req.Header.Set("X-Forwarded-Proto", "http")
|
||||
req.Header.Set("X-Forwarded-Host", "internal:8080")
|
||||
rec := httptest.NewRecorder()
|
||||
app.ServeHTTP(rec, req)
|
||||
Expect(actualURL).To(Equal("https://192.168.0.13:34567/"))
|
||||
})
|
||||
|
||||
It("combines the configured origin with a detected path prefix", func() {
|
||||
app := echo.New()
|
||||
actualURL := ""
|
||||
app.GET("/hello", func(c echo.Context) error {
|
||||
c.Set("_original_path", "/localai/hello")
|
||||
c.Set("_external_base_url", "https://ext.example")
|
||||
actualURL = BaseURL(c)
|
||||
return nil
|
||||
})
|
||||
req := httptest.NewRequest("GET", "/hello", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
app.ServeHTTP(rec, req)
|
||||
Expect(actualURL).To(Equal("https://ext.example/localai/"))
|
||||
})
|
||||
|
||||
It("ignores an empty override", func() {
|
||||
app := echo.New()
|
||||
actualURL := ""
|
||||
app.GET("/x", func(c echo.Context) error {
|
||||
c.Set("_external_base_url", "")
|
||||
actualURL = BaseURL(c)
|
||||
return nil
|
||||
})
|
||||
req := httptest.NewRequest("GET", "/x", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
app.ServeHTTP(rec, req)
|
||||
Expect(actualURL).To(Equal("http://example.com/"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user