Middleware handles some cookie mutation the requests. For performance of this, see 'BenchmarkHTTPCookieConfigMiddleware' This code is executed on every request, so efficiency is important. If making changes, please consider the performance implications and run benchmarks.
(next http.Handler)
| 1014 | // This code is executed on every request, so efficiency is important. |
| 1015 | // If making changes, please consider the performance implications and run benchmarks. |
| 1016 | func (cfg *HTTPCookieConfig) Middleware(next http.Handler) http.Handler { |
| 1017 | prefixed := make(map[string]struct{}) |
| 1018 | for name := range cookiesToPrefix { |
| 1019 | prefixed[cookieHostPrefix+name] = struct{}{} |
| 1020 | } |
| 1021 | return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { |
| 1022 | if !cfg.EnableHostPrefix { |
| 1023 | // If a deployment has this config on, then turned it off. Then some old __Host- |
| 1024 | // cookies could exist on the browsers of the clients. These cookies have no |
| 1025 | // impact, so we are going to ignore them if they exist (niche scenario) |
| 1026 | next.ServeHTTP(rw, r) |
| 1027 | return |
| 1028 | } |
| 1029 | |
| 1030 | // When 'EnableHostPrefix', some cookies are set with a `__Host-` prefix. This |
| 1031 | // middleware will strip any prefixes, so the backend is unaware of this security |
| 1032 | // feature. |
| 1033 | // |
| 1034 | // This code also handles any unprefixed cookies that are now invalid. |
| 1035 | cookies := r.Cookies() |
| 1036 | for i, c := range cookies { |
| 1037 | // If any cookies that should be prefixed are found without the prefix, remove |
| 1038 | // them from the client and the request. This is usually from a migration where |
| 1039 | // the prefix was just turned on. In any case, these cookies MUST be dropped |
| 1040 | if _, ok := cookiesToPrefix[c.Name]; ok { |
| 1041 | // Remove the cookie from the client to prevent any future requests from sending it. |
| 1042 | http.SetCookie(rw, &http.Cookie{ |
| 1043 | MaxAge: -1, // Delete |
| 1044 | Name: c.Name, |
| 1045 | Path: "/", |
| 1046 | }) |
| 1047 | // And remove it from the request so the rest of the code doesn't see it. |
| 1048 | cookies[i] = nil |
| 1049 | } |
| 1050 | |
| 1051 | // Only strip prefix's from the cookies we care about. Let other `__Host-` cookies be |
| 1052 | if _, ok := prefixed[c.Name]; ok { |
| 1053 | c.Name = strings.TrimPrefix(c.Name, cookieHostPrefix) |
| 1054 | } |
| 1055 | } |
| 1056 | |
| 1057 | // r.Cookies() returns copies, so we need to rebuild the header. |
| 1058 | r.Header.Del("Cookie") |
| 1059 | for _, c := range cookies { |
| 1060 | if c != nil { |
| 1061 | r.AddCookie(c) |
| 1062 | } |
| 1063 | } |
| 1064 | |
| 1065 | next.ServeHTTP(rw, r) |
| 1066 | }) |
| 1067 | } |
| 1068 | |
| 1069 | func (cfg *HTTPCookieConfig) Apply(c *http.Cookie) *http.Cookie { |
| 1070 | c.Secure = cfg.Secure.Value() |