| 
									
										
										
										
											2019-06-30 16:07:58 -06:00
										 |  |  | // Copyright 2015 Matthew Holt and The Caddy Authors | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | // You may obtain a copy of the License at | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and | 
					
						
							|  |  |  | // limitations under the License. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | package headers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-02 12:37:06 -06:00
										 |  |  | 	"github.com/caddyserver/caddy/v2" | 
					
						
							|  |  |  | 	"github.com/caddyserver/caddy/v2/modules/caddyhttp" | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	caddy.RegisterModule(Handler{}) | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | // Handler is a middleware which modifies request and response headers. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Changes to headers are applied immediately, except for the response | 
					
						
							|  |  |  | // headers when Deferred is true or when Required is set. In those cases, | 
					
						
							|  |  |  | // the changes are applied when the headers are written to the response. | 
					
						
							|  |  |  | // Note that deferred changes do not take effect if an error occurs later | 
					
						
							|  |  |  | // in the middleware chain. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Properties in this module accept placeholders. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Response header operations can be conditioned upon response status code | 
					
						
							|  |  |  | // and/or other header values. | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | type Handler struct { | 
					
						
							| 
									
										
										
										
											2019-05-22 12:32:36 -06:00
										 |  |  | 	Request  *HeaderOps     `json:"request,omitempty"` | 
					
						
							|  |  |  | 	Response *RespHeaderOps `json:"response,omitempty"` | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | // CaddyModule returns the Caddy module information. | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | func (Handler) CaddyModule() caddy.ModuleInfo { | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	return caddy.ModuleInfo{ | 
					
						
							| 
									
										
										
										
											2019-12-10 13:36:46 -07:00
										 |  |  | 		ID:  "http.handlers.headers", | 
					
						
							|  |  |  | 		New: func() caddy.Module { return new(Handler) }, | 
					
						
							| 
									
										
										
										
											2019-08-21 10:46:35 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | // Provision sets up h's configuration. | 
					
						
							| 
									
										
										
										
											2020-07-20 12:28:40 -06:00
										 |  |  | func (h *Handler) Provision(ctx caddy.Context) error { | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	if h.Request != nil { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:28:40 -06:00
										 |  |  | 		err := h.Request.Provision(ctx) | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if h.Response != nil { | 
					
						
							| 
									
										
										
										
											2020-07-20 12:28:40 -06:00
										 |  |  | 		err := h.Response.Provision(ctx) | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | // Validate ensures h's configuration is valid. | 
					
						
							|  |  |  | func (h Handler) Validate() error { | 
					
						
							|  |  |  | 	if h.Request != nil { | 
					
						
							|  |  |  | 		err := h.Request.validate() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if h.Response != nil { | 
					
						
							|  |  |  | 		err := h.Response.validate() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { | 
					
						
							| 
									
										
										
										
											2019-12-29 13:12:52 -07:00
										 |  |  | 	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) | 
					
						
							| 
									
										
										
										
											2019-09-11 18:48:37 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 	if h.Request != nil { | 
					
						
							|  |  |  | 		h.Request.ApplyToRequest(r) | 
					
						
							| 
									
										
										
										
											2019-09-11 18:48:37 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 14:36:26 -06:00
										 |  |  | 	if h.Response != nil { | 
					
						
							|  |  |  | 		if h.Response.Deferred || h.Response.Require != nil { | 
					
						
							|  |  |  | 			w = &responseWriterWrapper{ | 
					
						
							|  |  |  | 				ResponseWriterWrapper: &caddyhttp.ResponseWriterWrapper{ResponseWriter: w}, | 
					
						
							|  |  |  | 				replacer:              repl, | 
					
						
							|  |  |  | 				require:               h.Response.Require, | 
					
						
							|  |  |  | 				headerOps:             h.Response.HeaderOps, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 			h.Response.ApplyTo(w.Header(), repl) | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	return next.ServeHTTP(w, r) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | // HeaderOps defines manipulations for HTTP headers. | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | type HeaderOps struct { | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 	// Adds HTTP headers; does not replace any existing header fields. | 
					
						
							|  |  |  | 	Add http.Header `json:"add,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Sets HTTP headers; replaces existing header fields. | 
					
						
							|  |  |  | 	Set http.Header `json:"set,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Names of HTTP header fields to delete. | 
					
						
							|  |  |  | 	Delete []string `json:"delete,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Performs substring replacements of HTTP headers in-situ. | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	Replace map[string][]Replacement `json:"replace,omitempty"` | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:28:40 -06:00
										 |  |  | // Provision sets up the header operations. | 
					
						
							|  |  |  | func (ops *HeaderOps) Provision(_ caddy.Context) error { | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	for fieldName, replacements := range ops.Replace { | 
					
						
							|  |  |  | 		for i, r := range replacements { | 
					
						
							|  |  |  | 			if r.SearchRegexp != "" { | 
					
						
							|  |  |  | 				re, err := regexp.Compile(r.SearchRegexp) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return fmt.Errorf("replacement %d for header field '%s': %v", i, fieldName, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				replacements[i].re = re | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ops HeaderOps) validate() error { | 
					
						
							|  |  |  | 	for fieldName, replacements := range ops.Replace { | 
					
						
							|  |  |  | 		for _, r := range replacements { | 
					
						
							|  |  |  | 			if r.Search != "" && r.SearchRegexp != "" { | 
					
						
							|  |  |  | 				return fmt.Errorf("cannot specify both a substring search and a regular expression search for field '%s'", fieldName) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Replacement describes a string replacement, | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | // either a simple and fast substring search | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | // or a slower but more powerful regex search. | 
					
						
							|  |  |  | type Replacement struct { | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 	// The substring to search for. | 
					
						
							|  |  |  | 	Search string `json:"search,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The regular expression to search with. | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	SearchRegexp string `json:"search_regexp,omitempty"` | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// The string with which to replace matches. | 
					
						
							|  |  |  | 	Replace string `json:"replace,omitempty"` | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	re *regexp.Regexp | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | // RespHeaderOps defines manipulations for response headers. | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | type RespHeaderOps struct { | 
					
						
							|  |  |  | 	*HeaderOps | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If set, header operations will be deferred until | 
					
						
							|  |  |  | 	// they are written out and only performed if the | 
					
						
							|  |  |  | 	// response matches these criteria. | 
					
						
							|  |  |  | 	Require *caddyhttp.ResponseMatcher `json:"require,omitempty"` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If true, header operations will be deferred until | 
					
						
							|  |  |  | 	// they are written out. Superceded if Require is set. | 
					
						
							| 
									
										
										
										
											2020-02-04 11:05:32 -07:00
										 |  |  | 	// Usually you will need to set this to true if any | 
					
						
							|  |  |  | 	// fields are being deleted. | 
					
						
							| 
									
										
										
										
											2019-12-23 12:45:35 -07:00
										 |  |  | 	Deferred bool `json:"deferred,omitempty"` | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | // ApplyTo applies ops to hdr using repl. | 
					
						
							| 
									
										
										
										
											2019-12-29 13:12:52 -07:00
										 |  |  | func (ops HeaderOps) ApplyTo(hdr http.Header, repl *caddy.Replacer) { | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 	// add | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	for fieldName, vals := range ops.Add { | 
					
						
							| 
									
										
										
										
											2019-05-20 23:48:43 -06:00
										 |  |  | 		fieldName = repl.ReplaceAll(fieldName, "") | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 		for _, v := range vals { | 
					
						
							| 
									
										
										
										
											2019-05-20 23:48:43 -06:00
										 |  |  | 			hdr.Add(fieldName, repl.ReplaceAll(v, "")) | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 	// set | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	for fieldName, vals := range ops.Set { | 
					
						
							| 
									
										
										
										
											2019-05-20 23:48:43 -06:00
										 |  |  | 		fieldName = repl.ReplaceAll(fieldName, "") | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 		var newVals []string | 
					
						
							| 
									
										
										
										
											2019-05-20 23:48:43 -06:00
										 |  |  | 		for i := range vals { | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 			// append to new slice so we don't overwrite | 
					
						
							|  |  |  | 			// the original values in ops.Set | 
					
						
							|  |  |  | 			newVals = append(newVals, repl.ReplaceAll(vals[i], "")) | 
					
						
							| 
									
										
										
										
											2019-05-20 23:48:43 -06:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 		hdr.Set(fieldName, strings.Join(newVals, ",")) | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 	// delete | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	for _, fieldName := range ops.Delete { | 
					
						
							| 
									
										
										
										
											2019-05-20 23:48:43 -06:00
										 |  |  | 		hdr.Del(repl.ReplaceAll(fieldName, "")) | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 	// replace | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	for fieldName, replacements := range ops.Replace { | 
					
						
							|  |  |  | 		fieldName = repl.ReplaceAll(fieldName, "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 		// all fields... | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 		if fieldName == "*" { | 
					
						
							|  |  |  | 			for _, r := range replacements { | 
					
						
							|  |  |  | 				search := repl.ReplaceAll(r.Search, "") | 
					
						
							|  |  |  | 				replace := repl.ReplaceAll(r.Replace, "") | 
					
						
							|  |  |  | 				for fieldName, vals := range hdr { | 
					
						
							|  |  |  | 					for i := range vals { | 
					
						
							|  |  |  | 						if r.re != nil { | 
					
						
							|  |  |  | 							hdr[fieldName][i] = r.re.ReplaceAllString(hdr[fieldName][i], replace) | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							hdr[fieldName][i] = strings.ReplaceAll(hdr[fieldName][i], search, replace) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 		// ...or only with the named field | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 		for _, r := range replacements { | 
					
						
							|  |  |  | 			search := repl.ReplaceAll(r.Search, "") | 
					
						
							|  |  |  | 			replace := repl.ReplaceAll(r.Replace, "") | 
					
						
							|  |  |  | 			for i := range hdr[fieldName] { | 
					
						
							|  |  |  | 				if r.re != nil { | 
					
						
							|  |  |  | 					hdr[fieldName][i] = r.re.ReplaceAllString(hdr[fieldName][i], replace) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					hdr[fieldName][i] = strings.ReplaceAll(hdr[fieldName][i], search, replace) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | // ApplyToRequest applies ops to r, specially handling the Host | 
					
						
							|  |  |  | // header which the standard library does not include with the | 
					
						
							|  |  |  | // header map with all the others. This method mutates r.Host. | 
					
						
							|  |  |  | func (ops HeaderOps) ApplyToRequest(r *http.Request) { | 
					
						
							| 
									
										
										
										
											2019-12-29 13:12:52 -07:00
										 |  |  | 	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// capture the current Host header so we can | 
					
						
							|  |  |  | 	// reset to it when we're done | 
					
						
							|  |  |  | 	origHost, hadHost := r.Header["Host"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// append r.Host; this way, we know that our value | 
					
						
							|  |  |  | 	// was last in the list, and if an Add operation | 
					
						
							|  |  |  | 	// appended something else after it, that's probably | 
					
						
							|  |  |  | 	// fine because it's weird to have multiple Host | 
					
						
							|  |  |  | 	// headers anyway and presumably the one they added | 
					
						
							|  |  |  | 	// is the one they wanted | 
					
						
							|  |  |  | 	r.Header["Host"] = append(r.Header["Host"], r.Host) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// apply header operations | 
					
						
							|  |  |  | 	ops.ApplyTo(r.Header, repl) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// retrieve the last Host value (likely the one we appended) | 
					
						
							|  |  |  | 	if len(r.Header["Host"]) > 0 { | 
					
						
							|  |  |  | 		r.Host = r.Header["Host"][len(r.Header["Host"])-1] | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		r.Host = "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// reset the Host header slice | 
					
						
							|  |  |  | 	if hadHost { | 
					
						
							|  |  |  | 		r.Header["Host"] = origHost | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		delete(r.Header, "Host") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | // responseWriterWrapper defers response header | 
					
						
							|  |  |  | // operations until WriteHeader is called. | 
					
						
							|  |  |  | type responseWriterWrapper struct { | 
					
						
							|  |  |  | 	*caddyhttp.ResponseWriterWrapper | 
					
						
							| 
									
										
										
										
											2019-12-29 13:12:52 -07:00
										 |  |  | 	replacer    *caddy.Replacer | 
					
						
							| 
									
										
										
										
											2019-05-28 18:53:08 -06:00
										 |  |  | 	require     *caddyhttp.ResponseMatcher | 
					
						
							| 
									
										
										
										
											2019-05-22 12:32:36 -06:00
										 |  |  | 	headerOps   *HeaderOps | 
					
						
							| 
									
										
										
										
											2019-05-20 22:00:54 -06:00
										 |  |  | 	wroteHeader bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | func (rww *responseWriterWrapper) WriteHeader(status int) { | 
					
						
							| 
									
										
										
										
											2019-05-20 22:00:54 -06:00
										 |  |  | 	if rww.wroteHeader { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	rww.wroteHeader = true | 
					
						
							| 
									
										
										
										
											2019-05-28 18:53:08 -06:00
										 |  |  | 	if rww.require == nil || rww.require.Match(status, rww.ResponseWriterWrapper.Header()) { | 
					
						
							| 
									
										
										
										
											2019-09-14 13:22:48 -06:00
										 |  |  | 		if rww.headerOps != nil { | 
					
						
							|  |  |  | 			rww.headerOps.ApplyTo(rww.ResponseWriterWrapper.Header(), rww.replacer) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-05-28 18:53:08 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	rww.ResponseWriterWrapper.WriteHeader(status) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-14 11:58:28 -06:00
										 |  |  | func (rww *responseWriterWrapper) Write(d []byte) (int, error) { | 
					
						
							|  |  |  | 	if !rww.wroteHeader { | 
					
						
							|  |  |  | 		rww.WriteHeader(http.StatusOK) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return rww.ResponseWriterWrapper.Write(d) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | // Interface guards | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2019-09-13 16:24:51 -06:00
										 |  |  | 	_ caddy.Provisioner           = (*Handler)(nil) | 
					
						
							|  |  |  | 	_ caddyhttp.MiddlewareHandler = (*Handler)(nil) | 
					
						
							| 
									
										
										
										
											2019-05-20 15:46:47 -06:00
										 |  |  | 	_ caddyhttp.HTTPInterfaces    = (*responseWriterWrapper)(nil) | 
					
						
							|  |  |  | ) |