mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-31 02:27:19 -04:00 
			
		
		
		
	Use httpserver.IndexFile() to determine index files Test if middleware pushes indexfile when requesting directory Fix codereview issues Serve original request first, push later Revert "Serve original request first, push later" This reverts commit 2c66f01115747e5665ba7f2d33e2fd551dc31877.
		
			
				
	
	
		
			116 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package push
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/mholt/caddy/caddyhttp/httpserver"
 | |
| 	"github.com/mholt/caddy/caddyhttp/staticfiles"
 | |
| )
 | |
| 
 | |
| 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 {
 | |
| 		urlPath := r.URL.Path
 | |
| 		matches := httpserver.Path(urlPath).Matches(rule.Path)
 | |
| 		// Also check IndexPages when requesting a directory
 | |
| 		if !matches {
 | |
| 			_, matches = httpserver.IndexFile(h.Root, urlPath, staticfiles.IndexPages)
 | |
| 		}
 | |
| 		if matches {
 | |
| 			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",
 | |
| }
 |