func (s *Server) serveHTTP(w http.ResponseWriter, r *http.Request) (int, error) { // strip out the port because it's not used in virtual // hosting; the port is irrelevant because each listener // is on a different port. hostname, _, err := net.SplitHostPort(r.Host) if err != nil { hostname = r.Host } // look up the virtualhost; if no match, serve error vhost, pathPrefix := s.vhosts.Match(hostname + r.URL.Path) if vhost == nil { // check for ACME challenge even if vhost is nil; // could be a new host coming online soon if caddytls.HTTPChallengeHandler(w, r, caddytls.DefaultHTTPAlternatePort) { return 0, nil } // otherwise, log the error and write a message to the client remoteHost, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { remoteHost = r.RemoteAddr } WriteTextResponse(w, http.StatusNotFound, "No such site at "+s.Server.Addr) log.Printf("[INFO] %s - No such site at %s (Remote: %s, Referer: %s)", hostname, s.Server.Addr, remoteHost, r.Header.Get("Referer")) return 0, nil } // we still check for ACME challenge if the vhost exists, // because we must apply its HTTP challenge config settings if s.proxyHTTPChallenge(vhost, w, r) { return 0, nil } // trim the path portion of the site address from the beginning of // the URL path, so a request to example.com/foo/blog on the site // defined as example.com/foo appears as /blog instead of /foo/blog. if pathPrefix != "/" { r.URL.Path = strings.TrimPrefix(r.URL.Path, pathPrefix) if !strings.HasPrefix(r.URL.Path, "/") { r.URL.Path = "/" + r.URL.Path } } // Apply the path-based request body size limit // The error returned by MaxBytesReader is meant to be handled // by whichever middleware/plugin that receives it when calling // .Read() or a similar method on the request body if r.Body != nil { for _, pathlimit := range vhost.MaxRequestBodySizes { if Path(r.URL.Path).Matches(pathlimit.Path) { r.Body = MaxBytesReader(w, r.Body, pathlimit.Limit) break } } } return vhost.middlewareChain.ServeHTTP(w, r) }
// proxyHTTPChallenge solves the ACME HTTP challenge if r is the HTTP // request for the challenge. If it is, and if the request has been // fulfilled (response written), true is returned; false otherwise. // If you don't have a vhost, just call the challenge handler directly. func (s *Server) proxyHTTPChallenge(vhost *SiteConfig, w http.ResponseWriter, r *http.Request) bool { if vhost.Addr.Port != caddytls.HTTPChallengePort { return false } if vhost.TLS != nil && vhost.TLS.Manual { return false } altPort := caddytls.DefaultHTTPAlternatePort if vhost.TLS != nil && vhost.TLS.AltHTTPPort != "" { altPort = vhost.TLS.AltHTTPPort } return caddytls.HTTPChallengeHandler(w, r, altPort) }