diff --git a/docs/middlewares.md b/docs/middlewares.md index 959c85c..10eb922 100644 --- a/docs/middlewares.md +++ b/docs/middlewares.md @@ -71,8 +71,13 @@ Example: Hot-reloading is **supported**, you can **edit**, **rename** or **delete** files **without restarting**. Changes will be reflected after page reload Error page will be served if: -- status code is not in range of 200 to 300 -- content type is `text/html`, `application/xhtml+xml` or `text/plain` + +- route does not exist or domain does not match any of `match_domains` + +or + +- status code is not in range of 200 to 300, and +- content type is `text/html`, `application/xhtml+xml` or `text/plain` Error page will be served: diff --git a/internal/common/http.go b/internal/common/http.go index fff08ad..a9ea8b5 100644 --- a/internal/common/http.go +++ b/internal/common/http.go @@ -23,3 +23,5 @@ var ( return clone }() ) + +const StaticFilePathPrefix = "/$gperrorpage/" diff --git a/internal/route/http.go b/internal/route/http.go index 8c3710e..eecdec4 100755 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -1,9 +1,7 @@ package route import ( - "encoding/json" "fmt" - "slices" "sync" "net/http" @@ -11,6 +9,7 @@ import ( "strings" "github.com/sirupsen/logrus" + "github.com/yusing/go-proxy/internal/api/v1/error_page" "github.com/yusing/go-proxy/internal/common" "github.com/yusing/go-proxy/internal/docker/idlewatcher" E "github.com/yusing/go-proxy/internal/error" @@ -172,20 +171,18 @@ func (u *URL) MarshalText() (text []byte, err error) { func ProxyHandler(w http.ResponseWriter, r *http.Request) { mux, err := findMuxFunc(r.Host) if err != nil { - logrus.Error(E.Failure("request"). - Subjectf("%s %s", r.Method, r.URL.String()). - With(err)) - acceptTypes := r.Header.Values("Accept") - switch { - case slices.Contains(acceptTypes, "text/html"): - - case slices.Contains(acceptTypes, "application/json"): - w.WriteHeader(http.StatusNotFound) - json.NewEncoder(w).Encode(map[string]string{ - "error": err.Error(), - }) - default: - http.Error(w, err.Error(), http.StatusNotFound) + if !middleware.ServeStaticErrorPageFile(w, r) { + logrus.Error(E.Failure("request"). + Subjectf("%s %s", r.Method, r.URL.String()). + With(err)) + errorPage, ok := error_page.GetErrorPageByStatus(http.StatusNotFound) + if ok { + w.WriteHeader(http.StatusNotFound) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(errorPage) + } else { + http.Error(w, err.Error(), http.StatusNotFound) + } } return } diff --git a/internal/route/middleware/custom_error_page.go b/internal/route/middleware/custom_error_page.go index e42d505..9df41f8 100644 --- a/internal/route/middleware/custom_error_page.go +++ b/internal/route/middleware/custom_error_page.go @@ -10,40 +10,15 @@ import ( "github.com/sirupsen/logrus" "github.com/yusing/go-proxy/internal/api/v1/error_page" + "github.com/yusing/go-proxy/internal/common" gpHTTP "github.com/yusing/go-proxy/internal/http" ) -const staticFilePathPrefix = "/$gperrorpage/" - var CustomErrorPage = &Middleware{ before: func(next http.Handler, w ResponseWriter, r *Request) { - path := r.URL.Path - if path != "" && path[0] != '/' { - path = "/" + path + if !ServeStaticErrorPageFile(w, r) { + next.ServeHTTP(w, r) } - if strings.HasPrefix(path, staticFilePathPrefix) { - filename := path[len(staticFilePathPrefix):] - file, ok := error_page.GetStaticFile(filename) - if !ok { - http.NotFound(w, r) - errPageLogger.Errorf("unable to load resource %s", filename) - } else { - ext := filepath.Ext(filename) - switch ext { - case ".html": - w.Header().Set("Content-Type", "text/html; charset=utf-8") - case ".js": - w.Header().Set("Content-Type", "application/javascript; charset=utf-8") - case ".css": - w.Header().Set("Content-Type", "text/css; charset=utf-8") - default: - errPageLogger.Errorf("unexpected file type %q for %s", ext, filename) - } - w.Write(file) - } - return - } - next.ServeHTTP(w, r) }, modifyResponse: func(resp *Response) error { // only handles non-success status code and html/plain content type @@ -67,4 +42,34 @@ var CustomErrorPage = &Middleware{ }, } +func ServeStaticErrorPageFile(w http.ResponseWriter, r *http.Request) bool { + path := r.URL.Path + if path != "" && path[0] != '/' { + path = "/" + path + } + if strings.HasPrefix(path, common.StaticFilePathPrefix) { + filename := path[len(common.StaticFilePathPrefix):] + file, ok := error_page.GetStaticFile(filename) + if !ok { + errPageLogger.Errorf("unable to load resource %s", filename) + return false + } else { + ext := filepath.Ext(filename) + switch ext { + case ".html": + w.Header().Set("Content-Type", "text/html; charset=utf-8") + case ".js": + w.Header().Set("Content-Type", "application/javascript; charset=utf-8") + case ".css": + w.Header().Set("Content-Type", "text/css; charset=utf-8") + default: + errPageLogger.Errorf("unexpected file type %q for %s", ext, filename) + } + w.Write(file) + return true + } + } + return false +} + var errPageLogger = logrus.WithField("middleware", "error_page") diff --git a/schema/providers.schema.json b/schema/providers.schema.json index 3e08599..d3456e4 100644 --- a/schema/providers.schema.json +++ b/schema/providers.schema.json @@ -64,8 +64,7 @@ "port": {}, "no_tls_verify": {}, "path_patterns": {}, - "set_headers": {}, - "hide_headers": {} + "middlewares": {} }, "additionalProperties": false, "allOf": [ @@ -121,24 +120,8 @@ } ] }, - "set_headers": { - "type": "object", - "description": "Proxy headers to set", - "additionalProperties": { - "items": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - }, - "hide_headers": { - "type": "array", - "description": "Proxy headers to hide", - "items": { - "type": "string" - } + "middlewares": { + "type": "object" } } }, @@ -156,10 +139,7 @@ "path_patterns": { "not": true }, - "set_headers": { - "not": true - }, - "hide_headers": { + "middlewares": { "not": true } },