mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-03 19:17:29 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			109 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package push
 | 
						|
 | 
						|
import (
 | 
						|
	"net/http"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
						|
)
 | 
						|
 | 
						|
func (h Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
 | 
						|
	pusher, hasPusher := w.(http.Pusher)
 | 
						|
 | 
						|
	// no push possible, carry on
 | 
						|
	if !hasPusher {
 | 
						|
		return h.Next.ServeHTTP(w, r)
 | 
						|
	}
 | 
						|
 | 
						|
	// check if this is a request for the pushed resource (avoid recursion)
 | 
						|
	if _, exists := r.Header[pushHeader]; exists {
 | 
						|
		return h.Next.ServeHTTP(w, r)
 | 
						|
	}
 | 
						|
 | 
						|
	headers := h.filterProxiedHeaders(r.Header)
 | 
						|
 | 
						|
	// push first
 | 
						|
outer:
 | 
						|
	for _, rule := range h.Rules {
 | 
						|
		if httpserver.Path(r.URL.Path).Matches(rule.Path) {
 | 
						|
			for _, resource := range rule.Resources {
 | 
						|
				pushErr := pusher.Push(resource.Path, &http.PushOptions{
 | 
						|
					Method: resource.Method,
 | 
						|
					Header: h.mergeHeaders(headers, resource.Header),
 | 
						|
				})
 | 
						|
				if pushErr != nil {
 | 
						|
					// if we cannot push (either not supported or concurrent streams are full - break)
 | 
						|
					break outer
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// serve later
 | 
						|
	code, err := h.Next.ServeHTTP(w, r)
 | 
						|
 | 
						|
	// push resources returned in Link headers from upstream middlewares or proxied apps
 | 
						|
	if links, exists := w.Header()["Link"]; exists {
 | 
						|
		h.servePreloadLinks(pusher, headers, links)
 | 
						|
	}
 | 
						|
 | 
						|
	return code, err
 | 
						|
}
 | 
						|
 | 
						|
func (h Middleware) servePreloadLinks(pusher http.Pusher, headers http.Header, links []string) {
 | 
						|
	for _, link := range links {
 | 
						|
		parts := strings.Split(link, ";")
 | 
						|
 | 
						|
		if link == "" || strings.HasSuffix(link, "nopush") {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		target := strings.TrimSuffix(strings.TrimPrefix(parts[0], "<"), ">")
 | 
						|
 | 
						|
		err := pusher.Push(target, &http.PushOptions{
 | 
						|
			Method: http.MethodGet,
 | 
						|
			Header: headers,
 | 
						|
		})
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h Middleware) mergeHeaders(l, r http.Header) http.Header {
 | 
						|
	out := http.Header{}
 | 
						|
 | 
						|
	for k, v := range l {
 | 
						|
		out[k] = v
 | 
						|
	}
 | 
						|
 | 
						|
	for k, vv := range r {
 | 
						|
		for _, v := range vv {
 | 
						|
			out.Add(k, v)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return out
 | 
						|
}
 | 
						|
 | 
						|
func (h Middleware) filterProxiedHeaders(headers http.Header) http.Header {
 | 
						|
	filter := http.Header{}
 | 
						|
 | 
						|
	for _, header := range proxiedHeaders {
 | 
						|
		if val, ok := headers[header]; ok {
 | 
						|
			filter[header] = val
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return filter
 | 
						|
}
 | 
						|
 | 
						|
var proxiedHeaders = []string{
 | 
						|
	"Accept-Encoding",
 | 
						|
	"Accept-Language",
 | 
						|
	"Cache-Control",
 | 
						|
	"Host",
 | 
						|
	"User-Agent",
 | 
						|
}
 |